Implementation of processing MediaQualityThreshold in libimsmedia

1) Implementation of procesing MediaQualityThreshold to handle the array
type of RtpInctivity, PacketLoss, Jitter threshold and additional
parameters
2) Implementation of send the notification of MediaQualityStatus
3) Change the name of legacy MediaQuality to CallQuality to prevent the
   confusion.

Bug: 255862778
Test: atest ImsMediaNativeTests, verified by loopback test using ImsMediaTestingApp
Change-Id: Id634272210ec3c21fc6e9a775bdad8d5a49273cb
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQuality.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/CallQuality.h
similarity index 93%
rename from service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQuality.h
rename to service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/CallQuality.h
index 0c6498f..491a6f1 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQuality.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/CallQuality.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef IMS_MEDIA_QULITY_H
-#define IMS_MEDIA_QULITY_H
+#ifndef IMS_CALL_QULITY_H
+#define IMS_CALL_QULITY_H
 
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
@@ -35,12 +35,12 @@
  * @brief Implementation of CallQualty class in native
  *
  */
-class MediaQuality : public Parcelable
+class CallQuality : public Parcelable
 {
 public:
-    MediaQuality();
-    MediaQuality(const MediaQuality& quality);
-    virtual ~MediaQuality();
+    CallQuality();
+    CallQuality(const CallQuality& quality);
+    virtual ~CallQuality();
     enum
     {
         /** < 1% packet loss */
@@ -84,10 +84,10 @@
         AUDIO_QUALITY_EVS_FB,
     };
 
-    MediaQuality& operator=(const MediaQuality& quality);
-    bool operator==(const MediaQuality& quality) const;
-    bool operator!=(const MediaQuality& quality) const;
-    virtual status_t writeToParcel(Parcel* parcel) const;
+    CallQuality& operator=(const CallQuality& quality);
+    bool operator==(const CallQuality& quality) const;
+    bool operator!=(const CallQuality& quality) const;
+    virtual status_t writeToParcel(Parcel* out) const;
     virtual status_t readFromParcel(const Parcel* in);
 
     int32_t getDownlinkCallQualityLevel();
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQualityStatus.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQualityStatus.h
new file mode 100644
index 0000000..c7dcaeb
--- /dev/null
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQualityStatus.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_QUALITY_STATUS_H
+#define MEDIA_QUALITY_STATUS_H
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/Status.h>
+#include <stdint.h>
+
+namespace android
+{
+
+namespace telephony
+{
+
+namespace imsmedia
+{
+
+/** Native representation of android.telephony.imsmedia.MediaQualityStatus */
+class MediaQualityStatus : public Parcelable
+{
+public:
+    MediaQualityStatus();
+    MediaQualityStatus(const MediaQualityStatus& status);
+    virtual ~MediaQualityStatus();
+    MediaQualityStatus& operator=(const MediaQualityStatus& status);
+    bool operator==(const MediaQualityStatus& status) const;
+    bool operator!=(const MediaQualityStatus& status) const;
+    virtual status_t writeToParcel(Parcel* out) const;
+    virtual status_t readFromParcel(const Parcel* in);
+    void setRtpInactivityTimeMillis(int32_t time);
+    int32_t getRtpInactivityTimeMillis();
+    void setRtcpInactivityTimeMillis(int32_t time);
+    int32_t getRtcpInactivityTimeMillis();
+    void setRtpPacketLossRate(int32_t rate);
+    int32_t getRtpPacketLossRate();
+    void setRtpJitterMillis(int32_t jitter);
+    int32_t getRtpJitterMillis();
+
+private:
+    /**
+     * The rtp inactivity observed as per thresholds set by the MediaQualityThreshold API
+     */
+    int32_t mRtpInactivityTimeMillis;
+    /**
+     * The rtcp inactivity observed as per thresholds set by the MediaQualityThreshold API
+     */
+    int32_t mRtcpInactivityTimeMillis;
+    /**
+     * The rtp packet loss rate observed as per thresholds set by the MediaQualityThreshold API
+     */
+    int32_t mRtpPacketLossRate;
+    /**
+     * The rtp jitter observed as per thresholds set by MediaQualityThreshold API
+     */
+    int32_t mRtpJitterMillis;
+};
+
+}  // namespace imsmedia
+
+}  // namespace telephony
+
+}  // namespace android
+
+#endif
\ No newline at end of file
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQualityThreshold.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQualityThreshold.h
index 07dff80..ecb3398 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQualityThreshold.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQualityThreshold.h
@@ -21,6 +21,7 @@
 #include <binder/Parcelable.h>
 #include <binder/Status.h>
 #include <stdint.h>
+#include <vector>
 
 namespace android
 {
@@ -43,35 +44,47 @@
     bool operator!=(const MediaQualityThreshold& threshold) const;
     virtual status_t writeToParcel(Parcel* parcel) const;
     virtual status_t readFromParcel(const Parcel* in);
-    void setRtpInactivityTimerMillis(int32_t time);
-    int32_t getRtpInactivityTimerMillis();
+    void setRtpInactivityTimerMillis(std::vector<int32_t> times);
+    std::vector<int32_t> getRtpInactivityTimerMillis() const;
     void setRtcpInactivityTimerMillis(int32_t time);
-    int32_t getRtcpInactivityTimerMillis();
+    int32_t getRtcpInactivityTimerMillis() const;
+    void setRtpHysteresisTimeInMillis(int32_t time);
+    int32_t getRtpHysteresisTimeInMillis() const;
     void setRtpPacketLossDurationMillis(int32_t time);
-    int32_t getRtpPacketLossDurationMillis();
-    void setRtpPacketLossRate(int32_t rate);
-    int32_t getRtpPacketLossRate();
-    void setJitterDurationMillis(int32_t time);
-    int32_t getJitterDurationMillis();
-    void setRtpJitterMillis(int32_t time);
-    int32_t getRtpJitterMillis();
+    int32_t getRtpPacketLossDurationMillis() const;
+    void setRtpPacketLossRate(std::vector<int32_t> rates);
+    std::vector<int32_t> getRtpPacketLossRate() const;
+    void setRtpJitterMillis(std::vector<int32_t> jitters);
+    std::vector<int32_t> getRtpJitterMillis() const;
+    void setNotifyCurrentStatus(bool status);
+    bool getNotifyCurrentStatus() const;
 
 private:
-    /** Timer in milliseconds for monitoring RTP inactivity */
-    int32_t mRtpInactivityTimerMillis;
-    /** Timer in milliseconds for monitoring RTCP inactivity */
+    /** The timer in milliseconds for monitoring RTP inactivity */
+    std::vector<int32_t> mRtpInactivityTimerMillis;
+    /** The timer in milliseconds for monitoring RTCP inactivity */
     int32_t mRtcpInactivityTimerMillis;
-    /** Duration in milliseconds for monitoring the RTP packet loss rate */
+    /**
+     * Set the threshold hysteresis time for packet loss and jitter. This has a goal to prevent
+     * frequent ping-pong notification. So whenever a notifier needs to report the cross of
+     * threshold in opposite direction, this hysteresis timer should be respected.
+     */
+    int32_t mRtpHysteresisTimeInMillis;
+    /** Set the duration in milliseconds for monitoring the RTP packet loss rate */
     int32_t mRtpPacketLossDurationMillis;
     /**
      * Packet loss rate in percentage of (total number of packets lost) /
      * (total number of packets expected) during rtpPacketLossDurationMs
      */
-    int32_t mRtpPacketLossRate;
-    /** Duration in milliseconds for monitoring the jitter for RTP traffic */
-    int32_t mJitterDurationMillis;
+    std::vector<int32_t> mRtpPacketLossRate;
     /** RTP jitter threshold in milliseconds */
-    int32_t mRtpJitterMillis;
+    std::vector<int32_t> mRtpJitterMillis;
+    /**
+     * A flag indicating whether the client needs to be notify the current media quality status
+     * right after threshold is being set. True means the media stack should notify the client
+     * of the current status.
+     */
+    bool mNotifyCurrentStatus;
 };
 
 }  // namespace imsmedia
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQuality.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/CallQuality.cpp
similarity index 77%
rename from service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQuality.cpp
rename to service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/CallQuality.cpp
index 1c70bc9..b8e24af 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQuality.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/CallQuality.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <MediaQuality.h>
+#include <CallQuality.h>
 
 namespace android
 {
@@ -27,7 +27,7 @@
 
 #define DEFAULT_PARAM (-1)
 
-MediaQuality::MediaQuality()
+CallQuality::CallQuality()
 {
     mDownlinkCallQualityLevel = 0;
     mUplinkCallQualityLevel = 0;
@@ -52,7 +52,7 @@
     mNumRtpDuplicatePackets = 0;
 }
 
-MediaQuality::MediaQuality(const MediaQuality& quality)
+CallQuality::CallQuality(const CallQuality& quality)
 {
     mDownlinkCallQualityLevel = quality.mDownlinkCallQualityLevel;
     mUplinkCallQualityLevel = quality.mUplinkCallQualityLevel;
@@ -77,9 +77,9 @@
     mNumRtpDuplicatePackets = quality.mNumRtpDuplicatePackets;
 }
 
-MediaQuality::~MediaQuality() {}
+CallQuality::~CallQuality() {}
 
-MediaQuality& MediaQuality::operator=(const MediaQuality& quality)
+CallQuality& CallQuality::operator=(const CallQuality& quality)
 {
     if (this != &quality)
     {
@@ -108,7 +108,7 @@
     return *this;
 }
 
-bool MediaQuality::operator==(const MediaQuality& quality) const
+bool CallQuality::operator==(const CallQuality& quality) const
 {
     return (mDownlinkCallQualityLevel == quality.mDownlinkCallQualityLevel &&
             mUplinkCallQualityLevel == quality.mUplinkCallQualityLevel &&
@@ -133,7 +133,7 @@
             mNumRtpDuplicatePackets == quality.mNumRtpDuplicatePackets);
 }
 
-bool MediaQuality::operator!=(const MediaQuality& quality) const
+bool CallQuality::operator!=(const CallQuality& quality) const
 {
     return (mDownlinkCallQualityLevel != quality.mDownlinkCallQualityLevel ||
             mUplinkCallQualityLevel != quality.mUplinkCallQualityLevel ||
@@ -158,70 +158,70 @@
             mNumRtpDuplicatePackets != quality.mNumRtpDuplicatePackets);
 }
 
-status_t MediaQuality::writeToParcel(Parcel* parcel) const
+status_t CallQuality::writeToParcel(Parcel* out) const
 {
     status_t err;
-    err = parcel->writeInt32(mDownlinkCallQualityLevel);
+    err = out->writeInt32(mDownlinkCallQualityLevel);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mUplinkCallQualityLevel);
+    err = out->writeInt32(mUplinkCallQualityLevel);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mCallDuration);
+    err = out->writeInt32(mCallDuration);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mNumRtpPacketsTransmitted);
+    err = out->writeInt32(mNumRtpPacketsTransmitted);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mNumRtpPacketsReceived);
+    err = out->writeInt32(mNumRtpPacketsReceived);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mNumRtpPacketsTransmittedLost);
+    err = out->writeInt32(mNumRtpPacketsTransmittedLost);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mNumRtpPacketsNotReceived);
+    err = out->writeInt32(mNumRtpPacketsNotReceived);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mAverageRelativeJitter);
+    err = out->writeInt32(mAverageRelativeJitter);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mMaxRelativeJitter);
+    err = out->writeInt32(mMaxRelativeJitter);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mAverageRoundTripTime);
+    err = out->writeInt32(mAverageRoundTripTime);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mCodecType);
+    err = out->writeInt32(mCodecType);
     if (err != NO_ERROR)
     {
         return err;
@@ -229,63 +229,63 @@
 
     int32_t value = 0;
     mRtpInactivityDetected ? value = 1 : value = 0;
-    err = parcel->writeInt32(value);
+    err = out->writeInt32(value);
     if (err != NO_ERROR)
     {
         return err;
     }
 
     mRxSilenceDetected ? value = 1 : value = 0;
-    err = parcel->writeInt32(value);
+    err = out->writeInt32(value);
     if (err != NO_ERROR)
     {
         return err;
     }
 
     mTxSilenceDetected ? value = 1 : value = 0;
-    err = parcel->writeInt32(value);
+    err = out->writeInt32(value);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mNumVoiceFrames);
+    err = out->writeInt32(mNumVoiceFrames);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mNumNoDataFrames);
+    err = out->writeInt32(mNumNoDataFrames);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mNumDroppedRtpPackets);
+    err = out->writeInt32(mNumDroppedRtpPackets);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt64(mMinPlayoutDelayMillis);
+    err = out->writeInt64(mMinPlayoutDelayMillis);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt64(mMaxPlayoutDelayMillis);
+    err = out->writeInt64(mMaxPlayoutDelayMillis);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mNumRtpSidPacketsReceived);
+    err = out->writeInt32(mNumRtpSidPacketsReceived);
     if (err != NO_ERROR)
     {
         return err;
     }
 
-    err = parcel->writeInt32(mNumRtpDuplicatePackets);
+    err = out->writeInt32(mNumRtpDuplicatePackets);
     if (err != NO_ERROR)
     {
         return err;
@@ -294,7 +294,7 @@
     return NO_ERROR;
 }
 
-status_t MediaQuality::readFromParcel(const Parcel* in)
+status_t CallQuality::readFromParcel(const Parcel* in)
 {
     status_t err;
     err = in->readInt32(&mDownlinkCallQualityLevel);
@@ -433,212 +433,212 @@
     return NO_ERROR;
 }
 
-int MediaQuality::getDownlinkCallQualityLevel()
+int CallQuality::getDownlinkCallQualityLevel()
 {
     return mDownlinkCallQualityLevel;
 }
 
-void MediaQuality::setDownlinkCallQualityLevel(const int level)
+void CallQuality::setDownlinkCallQualityLevel(const int level)
 {
     mDownlinkCallQualityLevel = level;
 }
 
-int MediaQuality::getUplinkCallQualityLevel()
+int CallQuality::getUplinkCallQualityLevel()
 {
     return mUplinkCallQualityLevel;
 }
 
-void MediaQuality::setUplinkCallQualityLevel(const int level)
+void CallQuality::setUplinkCallQualityLevel(const int level)
 {
     mUplinkCallQualityLevel = level;
 }
 
-int MediaQuality::getCallDuration()
+int CallQuality::getCallDuration()
 {
     return mCallDuration;
 }
 
-void MediaQuality::setCallDuration(const int duration)
+void CallQuality::setCallDuration(const int duration)
 {
     mCallDuration = duration;
 }
 
-int MediaQuality::getNumRtpPacketsTransmitted()
+int CallQuality::getNumRtpPacketsTransmitted()
 {
     return mNumRtpPacketsTransmitted;
 }
 
-void MediaQuality::setNumRtpPacketsTransmitted(const int num)
+void CallQuality::setNumRtpPacketsTransmitted(const int num)
 {
     mNumRtpPacketsTransmitted = num;
 }
 
-int MediaQuality::getNumRtpPacketsReceived()
+int CallQuality::getNumRtpPacketsReceived()
 {
     return mNumRtpPacketsReceived;
 }
 
-void MediaQuality::setNumRtpPacketsReceived(const int num)
+void CallQuality::setNumRtpPacketsReceived(const int num)
 {
     mNumRtpPacketsReceived = num;
 }
 
-int MediaQuality::getNumRtpPacketsTransmittedLost()
+int CallQuality::getNumRtpPacketsTransmittedLost()
 {
     return mNumRtpPacketsTransmittedLost;
 }
 
-void MediaQuality::setNumRtpPacketsTransmittedLost(const int num)
+void CallQuality::setNumRtpPacketsTransmittedLost(const int num)
 {
     mNumRtpPacketsTransmittedLost = num;
 }
 
-int MediaQuality::getNumRtpPacketsNotReceived()
+int CallQuality::getNumRtpPacketsNotReceived()
 {
     return mNumRtpPacketsNotReceived;
 }
 
-void MediaQuality::setNumRtpPacketsNotReceived(const int num)
+void CallQuality::setNumRtpPacketsNotReceived(const int num)
 {
     mNumRtpPacketsNotReceived = num;
 }
 
-int MediaQuality::getAverageRelativeJitter()
+int CallQuality::getAverageRelativeJitter()
 {
     return mAverageRelativeJitter;
 }
 
-void MediaQuality::setAverageRelativeJitter(const int jitter)
+void CallQuality::setAverageRelativeJitter(const int jitter)
 {
     mAverageRelativeJitter = jitter;
 }
 
-int MediaQuality::getMaxRelativeJitter()
+int CallQuality::getMaxRelativeJitter()
 {
     return mMaxRelativeJitter;
 }
 
-void MediaQuality::setMaxRelativeJitter(const int jitter)
+void CallQuality::setMaxRelativeJitter(const int jitter)
 {
     mMaxRelativeJitter = jitter;
 }
 
-int MediaQuality::getAverageRoundTripTime()
+int CallQuality::getAverageRoundTripTime()
 {
     return mAverageRoundTripTime;
 }
 
-void MediaQuality::setAverageRoundTripTime(const int time)
+void CallQuality::setAverageRoundTripTime(const int time)
 {
     mAverageRoundTripTime = time;
 }
 
-int MediaQuality::getCodecType()
+int CallQuality::getCodecType()
 {
     return mCodecType;
 }
 
-void MediaQuality::setCodecType(const int type)
+void CallQuality::setCodecType(const int type)
 {
     mCodecType = type;
 }
 
-bool MediaQuality::getRtpInactivityDetected()
+bool CallQuality::getRtpInactivityDetected()
 {
     return mRtpInactivityDetected;
 }
 
-void MediaQuality::setRtpInactivityDetected(const bool detected)
+void CallQuality::setRtpInactivityDetected(const bool detected)
 {
     mRtpInactivityDetected = detected;
 }
 
-bool MediaQuality::getRxSilenceDetected()
+bool CallQuality::getRxSilenceDetected()
 {
     return mRxSilenceDetected;
 }
 
-void MediaQuality::setRxSilenceDetected(const bool detected)
+void CallQuality::setRxSilenceDetected(const bool detected)
 {
     mRxSilenceDetected = detected;
 }
 
-bool MediaQuality::getTxSilenceDetected()
+bool CallQuality::getTxSilenceDetected()
 {
     return mTxSilenceDetected;
 }
 
-void MediaQuality::setTxSilenceDetected(const bool detected)
+void CallQuality::setTxSilenceDetected(const bool detected)
 {
     mTxSilenceDetected = detected;
 }
 
-int MediaQuality::getNumVoiceFrames()
+int CallQuality::getNumVoiceFrames()
 {
     return mNumVoiceFrames;
 }
 
-void MediaQuality::setNumVoiceFrames(const int num)
+void CallQuality::setNumVoiceFrames(const int num)
 {
     mNumVoiceFrames = num;
 }
 
-int MediaQuality::getNumNoDataFrames()
+int CallQuality::getNumNoDataFrames()
 {
     return mNumNoDataFrames;
 }
 
-void MediaQuality::setNumNoDataFrames(const int num)
+void CallQuality::setNumNoDataFrames(const int num)
 {
     mNumNoDataFrames = num;
 }
 
-int MediaQuality::getNumDroppedRtpPackets()
+int CallQuality::getNumDroppedRtpPackets()
 {
     return mNumDroppedRtpPackets;
 }
 
-void MediaQuality::setNumDroppedRtpPackets(const int num)
+void CallQuality::setNumDroppedRtpPackets(const int num)
 {
     mNumDroppedRtpPackets = num;
 }
 
-int64_t MediaQuality::getMinPlayoutDelayMillis()
+int64_t CallQuality::getMinPlayoutDelayMillis()
 {
     return mMinPlayoutDelayMillis;
 }
 
-void MediaQuality::setMinPlayoutDelayMillis(const int64_t delay)
+void CallQuality::setMinPlayoutDelayMillis(const int64_t delay)
 {
     mMinPlayoutDelayMillis = delay;
 }
 
-int64_t MediaQuality::getMaxPlayoutDelayMillis()
+int64_t CallQuality::getMaxPlayoutDelayMillis()
 {
     return mMaxPlayoutDelayMillis;
 }
 
-void MediaQuality::setMaxPlayoutDelayMillis(const int64_t delay)
+void CallQuality::setMaxPlayoutDelayMillis(const int64_t delay)
 {
     mMaxPlayoutDelayMillis = delay;
 }
 
-int MediaQuality::getNumRtpSidPacketsReceived()
+int CallQuality::getNumRtpSidPacketsReceived()
 {
     return mNumRtpSidPacketsReceived;
 }
 
-void MediaQuality::setNumRtpSidPacketsReceived(const int num)
+void CallQuality::setNumRtpSidPacketsReceived(const int num)
 {
     mNumRtpSidPacketsReceived = num;
 }
 
-int MediaQuality::getNumRtpDuplicatePackets()
+int CallQuality::getNumRtpDuplicatePackets()
 {
     return mNumRtpDuplicatePackets;
 }
 
-void MediaQuality::setNumRtpDuplicatePackets(const int num)
+void CallQuality::setNumRtpDuplicatePackets(const int num)
 {
     mNumRtpDuplicatePackets = num;
 }
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQualityStatus.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQualityStatus.cpp
new file mode 100644
index 0000000..66b5a8f
--- /dev/null
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQualityStatus.cpp
@@ -0,0 +1,137 @@
+/**
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <MediaQualityStatus.h>
+
+namespace android
+{
+
+namespace telephony
+{
+
+namespace imsmedia
+{
+
+MediaQualityStatus::MediaQualityStatus()
+{
+    mRtpInactivityTimeMillis = 0;
+    mRtcpInactivityTimeMillis = 0;
+    mRtpPacketLossRate = 0;
+    mRtpJitterMillis = 0;
+}
+
+MediaQualityStatus::MediaQualityStatus(const MediaQualityStatus& status)
+{
+    mRtpInactivityTimeMillis = status.mRtpInactivityTimeMillis;
+    mRtcpInactivityTimeMillis = status.mRtcpInactivityTimeMillis;
+    mRtpPacketLossRate = status.mRtpPacketLossRate;
+    mRtpJitterMillis = status.mRtpJitterMillis;
+}
+
+MediaQualityStatus::~MediaQualityStatus() {}
+
+MediaQualityStatus& MediaQualityStatus::operator=(const MediaQualityStatus& status)
+{
+    if (this != &status)
+    {
+        mRtpInactivityTimeMillis = status.mRtpInactivityTimeMillis;
+        mRtcpInactivityTimeMillis = status.mRtcpInactivityTimeMillis;
+        mRtpPacketLossRate = status.mRtpPacketLossRate;
+        mRtpJitterMillis = status.mRtpJitterMillis;
+    }
+
+    return *this;
+}
+
+bool MediaQualityStatus::operator==(const MediaQualityStatus& status) const
+{
+    return (mRtpInactivityTimeMillis == status.mRtpInactivityTimeMillis &&
+            mRtcpInactivityTimeMillis == status.mRtcpInactivityTimeMillis &&
+            mRtpPacketLossRate == status.mRtpPacketLossRate &&
+            mRtpJitterMillis == status.mRtpJitterMillis);
+}
+
+bool MediaQualityStatus::operator!=(const MediaQualityStatus& status) const
+{
+    return (mRtpInactivityTimeMillis != status.mRtpInactivityTimeMillis ||
+            mRtcpInactivityTimeMillis != status.mRtcpInactivityTimeMillis ||
+            mRtpPacketLossRate != status.mRtpPacketLossRate ||
+            mRtpJitterMillis != status.mRtpJitterMillis);
+}
+
+status_t MediaQualityStatus::writeToParcel(Parcel* out) const
+{
+    out->writeInt32(mRtpInactivityTimeMillis);
+    out->writeInt32(mRtcpInactivityTimeMillis);
+    out->writeInt32(mRtpPacketLossRate);
+    out->writeInt32(mRtpJitterMillis);
+    return NO_ERROR;
+}
+
+status_t MediaQualityStatus::readFromParcel(const Parcel* in)
+{
+    in->readInt32(&mRtpInactivityTimeMillis);
+    in->readInt32(&mRtcpInactivityTimeMillis);
+    in->readInt32(&mRtpPacketLossRate);
+    in->readInt32(&mRtpJitterMillis);
+    return NO_ERROR;
+}
+
+void MediaQualityStatus::setRtpInactivityTimeMillis(int32_t time)
+{
+    mRtpInactivityTimeMillis = time;
+}
+
+int32_t MediaQualityStatus::getRtpInactivityTimeMillis()
+{
+    return mRtpInactivityTimeMillis;
+}
+
+void MediaQualityStatus::setRtcpInactivityTimeMillis(int32_t time)
+{
+    mRtcpInactivityTimeMillis = time;
+}
+
+int32_t MediaQualityStatus::getRtcpInactivityTimeMillis()
+{
+    return mRtcpInactivityTimeMillis;
+}
+
+void MediaQualityStatus::setRtpPacketLossRate(int32_t rate)
+{
+    mRtpPacketLossRate = rate;
+}
+
+int32_t MediaQualityStatus::getRtpPacketLossRate()
+{
+    return mRtpPacketLossRate;
+}
+
+void MediaQualityStatus::setRtpJitterMillis(int32_t jitter)
+{
+    mRtpJitterMillis = jitter;
+}
+
+int32_t MediaQualityStatus::getRtpJitterMillis()
+{
+    return mRtpJitterMillis;
+}
+
+}  // namespace imsmedia
+
+}  // namespace telephony
+
+}  // namespace android
\ No newline at end of file
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQualityThreshold.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQualityThreshold.cpp
index d115f35..f0ca147 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQualityThreshold.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQualityThreshold.cpp
@@ -27,22 +27,24 @@
 
 MediaQualityThreshold::MediaQualityThreshold()
 {
-    mRtpInactivityTimerMillis = 0;
+    mRtpInactivityTimerMillis.clear();
     mRtcpInactivityTimerMillis = 0;
+    mRtpHysteresisTimeInMillis = 0;
     mRtpPacketLossDurationMillis = 0;
-    mRtpPacketLossRate = 0;
-    mJitterDurationMillis = 0;
-    mRtpJitterMillis = 0;
+    mRtpPacketLossRate.clear();
+    mRtpJitterMillis.clear();
+    mNotifyCurrentStatus = false;
 }
 
 MediaQualityThreshold::MediaQualityThreshold(const MediaQualityThreshold& threshold)
 {
     mRtpInactivityTimerMillis = threshold.mRtpInactivityTimerMillis;
     mRtcpInactivityTimerMillis = threshold.mRtcpInactivityTimerMillis;
+    mRtpHysteresisTimeInMillis = threshold.mRtpHysteresisTimeInMillis;
     mRtpPacketLossDurationMillis = threshold.mRtpPacketLossDurationMillis;
     mRtpPacketLossRate = threshold.mRtpPacketLossRate;
-    mJitterDurationMillis = threshold.mJitterDurationMillis;
     mRtpJitterMillis = threshold.mRtpJitterMillis;
+    mNotifyCurrentStatus = threshold.mNotifyCurrentStatus;
 }
 
 MediaQualityThreshold::~MediaQualityThreshold() {}
@@ -53,10 +55,11 @@
     {
         mRtpInactivityTimerMillis = threshold.mRtpInactivityTimerMillis;
         mRtcpInactivityTimerMillis = threshold.mRtcpInactivityTimerMillis;
+        mRtpHysteresisTimeInMillis = threshold.mRtpHysteresisTimeInMillis;
         mRtpPacketLossDurationMillis = threshold.mRtpPacketLossDurationMillis;
         mRtpPacketLossRate = threshold.mRtpPacketLossRate;
-        mJitterDurationMillis = threshold.mJitterDurationMillis;
         mRtpJitterMillis = threshold.mRtpJitterMillis;
+        mNotifyCurrentStatus = threshold.mNotifyCurrentStatus;
     }
     return *this;
 }
@@ -65,112 +68,97 @@
 {
     return (mRtpInactivityTimerMillis == threshold.mRtpInactivityTimerMillis &&
             mRtcpInactivityTimerMillis == threshold.mRtcpInactivityTimerMillis &&
+            mRtpHysteresisTimeInMillis == threshold.mRtpHysteresisTimeInMillis &&
             mRtpPacketLossDurationMillis == threshold.mRtpPacketLossDurationMillis &&
             mRtpPacketLossRate == threshold.mRtpPacketLossRate &&
-            mJitterDurationMillis == threshold.mJitterDurationMillis &&
-            mRtpJitterMillis == threshold.mRtpJitterMillis);
+            mRtpJitterMillis == threshold.mRtpJitterMillis &&
+            mNotifyCurrentStatus == threshold.mNotifyCurrentStatus);
 }
 
 bool MediaQualityThreshold::operator!=(const MediaQualityThreshold& threshold) const
 {
     return (mRtpInactivityTimerMillis != threshold.mRtpInactivityTimerMillis ||
             mRtcpInactivityTimerMillis != threshold.mRtcpInactivityTimerMillis ||
+            mRtpHysteresisTimeInMillis != threshold.mRtpHysteresisTimeInMillis ||
             mRtpPacketLossDurationMillis != threshold.mRtpPacketLossDurationMillis ||
             mRtpPacketLossRate != threshold.mRtpPacketLossRate ||
-            mJitterDurationMillis != threshold.mJitterDurationMillis ||
-            mRtpJitterMillis != threshold.mRtpJitterMillis);
+            mRtpJitterMillis != threshold.mRtpJitterMillis ||
+            mNotifyCurrentStatus != threshold.mNotifyCurrentStatus);
 }
 
 status_t MediaQualityThreshold::writeToParcel(Parcel* out) const
 {
-    status_t err;
-    err = out->writeInt32(mRtpInactivityTimerMillis);
-    if (err != NO_ERROR)
+    out->writeInt32(mRtpInactivityTimerMillis.size());
+
+    for (auto& i : mRtpInactivityTimerMillis)
     {
-        return err;
+        out->writeInt32(i);
     }
 
-    err = out->writeInt32(mRtcpInactivityTimerMillis);
-    if (err != NO_ERROR)
+    out->writeInt32(mRtcpInactivityTimerMillis);
+    out->writeInt32(mRtpHysteresisTimeInMillis);
+    out->writeInt32(mRtpPacketLossDurationMillis);
+    out->writeInt32(mRtpPacketLossRate.size());
+
+    for (auto& i : mRtpPacketLossRate)
     {
-        return err;
+        out->writeInt32(i);
     }
 
-    err = out->writeInt32(mRtpPacketLossDurationMillis);
-    if (err != NO_ERROR)
+    out->writeInt32(mRtpJitterMillis.size());
+
+    for (auto& i : mRtpJitterMillis)
     {
-        return err;
+        out->writeInt32(i);
     }
 
-    err = out->writeInt32(mRtpPacketLossRate);
-    if (err != NO_ERROR)
-    {
-        return err;
-    }
-
-    err = out->writeInt32(mJitterDurationMillis);
-    if (err != NO_ERROR)
-    {
-        return err;
-    }
-
-    err = out->writeInt32(mRtpJitterMillis);
-    if (err != NO_ERROR)
-    {
-        return err;
-    }
-
+    out->writeInt32(mNotifyCurrentStatus ? 1 : 0);
     return NO_ERROR;
 }
 
 status_t MediaQualityThreshold::readFromParcel(const Parcel* in)
 {
-    status_t err;
-    err = in->readInt32(&mRtpInactivityTimerMillis);
-    if (err != NO_ERROR)
+    int32_t arrayLength = 0;
+    in->readInt32(&arrayLength);
+    mRtpInactivityTimerMillis.resize(arrayLength);
+
+    for (int32_t i = 0; i < arrayLength; i++)
     {
-        return err;
+        in->readInt32(&mRtpInactivityTimerMillis[i]);
     }
 
-    err = in->readInt32(&mRtcpInactivityTimerMillis);
-    if (err != NO_ERROR)
+    in->readInt32(&mRtcpInactivityTimerMillis);
+    in->readInt32(&mRtpHysteresisTimeInMillis);
+    in->readInt32(&mRtpPacketLossDurationMillis);
+    in->readInt32(&arrayLength);
+    mRtpPacketLossRate.resize(arrayLength);
+
+    for (int32_t i = 0; i < arrayLength; i++)
     {
-        return err;
+        in->readInt32(&mRtpPacketLossRate[i]);
     }
 
-    err = in->readInt32(&mRtpPacketLossDurationMillis);
-    if (err != NO_ERROR)
+    in->readInt32(&arrayLength);
+    mRtpJitterMillis.resize(arrayLength);
+
+    for (int32_t i = 0; i < arrayLength; i++)
     {
-        return err;
+        in->readInt32(&mRtpJitterMillis[i]);
     }
 
-    err = in->readInt32(&mRtpPacketLossRate);
-    if (err != NO_ERROR)
-    {
-        return err;
-    }
-
-    err = in->readInt32(&mJitterDurationMillis);
-    if (err != NO_ERROR)
-    {
-        return err;
-    }
-
-    err = in->readInt32(&mRtpJitterMillis);
-    if (err != NO_ERROR)
-    {
-        return err;
-    }
+    int32_t value;
+    in->readInt32(&value);
+    value == 1 ? mNotifyCurrentStatus = true : mNotifyCurrentStatus = false;
 
     return NO_ERROR;
 }
 
-void MediaQualityThreshold::setRtpInactivityTimerMillis(int32_t time)
+void MediaQualityThreshold::setRtpInactivityTimerMillis(std::vector<int32_t> time)
 {
     mRtpInactivityTimerMillis = time;
 }
 
-int32_t MediaQualityThreshold::getRtpInactivityTimerMillis()
+std::vector<int32_t> MediaQualityThreshold::getRtpInactivityTimerMillis() const
 {
     return mRtpInactivityTimerMillis;
 }
@@ -180,51 +168,61 @@
     mRtcpInactivityTimerMillis = time;
 }
 
-int32_t MediaQualityThreshold::getRtcpInactivityTimerMillis()
+int32_t MediaQualityThreshold::getRtcpInactivityTimerMillis() const
 {
     return mRtcpInactivityTimerMillis;
 }
 
+void MediaQualityThreshold::setRtpHysteresisTimeInMillis(int32_t time)
+{
+    mRtpHysteresisTimeInMillis = time;
+}
+
+int32_t MediaQualityThreshold::getRtpHysteresisTimeInMillis() const
+{
+    return mRtpHysteresisTimeInMillis;
+}
+
 void MediaQualityThreshold::setRtpPacketLossDurationMillis(int32_t time)
 {
     mRtpPacketLossDurationMillis = time;
 }
 
-int32_t MediaQualityThreshold::getRtpPacketLossDurationMillis()
+int32_t MediaQualityThreshold::getRtpPacketLossDurationMillis() const
 {
     return mRtpPacketLossDurationMillis;
 }
 
-void MediaQualityThreshold::setRtpPacketLossRate(int32_t rate)
+void MediaQualityThreshold::setRtpPacketLossRate(std::vector<int32_t> rate)
 {
     mRtpPacketLossRate = rate;
 }
 
-int32_t MediaQualityThreshold::getRtpPacketLossRate()
+std::vector<int32_t> MediaQualityThreshold::getRtpPacketLossRate() const
 {
     return mRtpPacketLossRate;
 }
 
-void MediaQualityThreshold::setJitterDurationMillis(int32_t rate)
-{
-    mJitterDurationMillis = rate;
-}
-
-int32_t MediaQualityThreshold::getJitterDurationMillis()
-{
-    return mJitterDurationMillis;
-}
-
-void MediaQualityThreshold::setRtpJitterMillis(int32_t jitter)
+void MediaQualityThreshold::setRtpJitterMillis(std::vector<int32_t> jitter)
 {
     mRtpJitterMillis = jitter;
 }
 
-int32_t MediaQualityThreshold::getRtpJitterMillis()
+std::vector<int32_t> MediaQualityThreshold::getRtpJitterMillis() const
 {
     return mRtpJitterMillis;
 }
 
+void MediaQualityThreshold::setNotifyCurrentStatus(bool status)
+{
+    mNotifyCurrentStatus = status;
+}
+
+bool MediaQualityThreshold::getNotifyCurrentStatus() const
+{
+    return mNotifyCurrentStatus;
+}
+
 }  // namespace imsmedia
 
 }  // namespace telephony
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBuffer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBuffer.cpp
index fb8b00e..38b59c3 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBuffer.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBuffer.cpp
@@ -202,7 +202,7 @@
     packet->ssrc = mSsrc;
     packet->seqNum = nSeqNum;
     packet->jitter = jitter;
-    packet->delay = ImsMediaTimer::GetTimeInMilliSeconds();
+    packet->arrival = ImsMediaTimer::GetTimeInMilliSeconds();
     mCallback->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
 
     if (nBufferSize == 0)
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp
index fa3d1e1..faabe4f 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp
@@ -17,6 +17,7 @@
 #include <AudioManager.h>
 #include <ImsMediaTrace.h>
 #include <ImsMediaNetworkUtil.h>
+#include <MediaQualityStatus.h>
 
 using namespace android;
 
@@ -455,13 +456,18 @@
         case kAudioRtpHeaderExtensionInd:
             // TODO : add implementation
             break;
-        case kAudioMediaInactivityInd:
-        case kAudioPacketLossInd:
-        case kAudioJitterInd:
+        case kAudioMediaQualityStatusInd:
+        {
             parcel.writeInt32(event);
-            parcel.writeInt32(static_cast<int>(paramA));
-            AudioManager::getInstance()->sendResponse(sessionId, parcel);
-            break;
+            MediaQualityStatus* status = reinterpret_cast<MediaQualityStatus*>(paramA);
+            if (status != nullptr)
+            {
+                status->writeToParcel(&parcel);
+                AudioManager::getInstance()->sendResponse(sessionId, parcel);
+                delete status;
+            }
+        }
+        break;
         case kAudioTriggerAnbrQueryInd:
             /** TODO: add implementation */
             break;
@@ -474,7 +480,7 @@
         case kAudioCallQualityChangedInd:
         {
             parcel.writeInt32(event);
-            MediaQuality* quality = reinterpret_cast<MediaQuality*>(paramA);
+            CallQuality* quality = reinterpret_cast<CallQuality*>(paramA);
             if (quality != nullptr)
             {
                 quality->writeToParcel(&parcel);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp
index 15ac67d..b2bb681 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp
@@ -615,17 +615,9 @@
             ImsMediaEventHandler::SendEvent(
                     "AUDIO_RESPONSE_EVENT", kAudioRtpHeaderExtensionInd, 0, 0);
             break;
-        case kImsMediaEventMediaInactivity:
-            ImsMediaEventHandler::SendEvent(
-                    "AUDIO_RESPONSE_EVENT", kAudioMediaInactivityInd, mSessionId, param1, param2);
-            break;
-        case kImsMediaEventPacketLoss:
-            ImsMediaEventHandler::SendEvent(
-                    "AUDIO_RESPONSE_EVENT", kAudioPacketLossInd, mSessionId, param1);
-            break;
-        case kImsMediaEventNotifyJitter:
-            ImsMediaEventHandler::SendEvent(
-                    "AUDIO_RESPONSE_EVENT", kAudioJitterInd, mSessionId, param1);
+        case kImsMediaEventMediaQualityStatus:
+            ImsMediaEventHandler::SendEvent("AUDIO_RESPONSE_EVENT", kAudioMediaQualityStatusInd,
+                    mSessionId, param1, param2);
             break;
         case kAudioTriggerAnbrQueryInd:
             /** TODO: add implementation */
@@ -664,30 +656,9 @@
     IMLOGI0("[setMediaQualityThreshold]");
     mThreshold = threshold;
 
-    for (auto& graph : mListGraphRtpRx)
-    {
-        if (graph != nullptr && graph->getState() == kStreamStateRunning)
-        {
-            graph->setMediaQualityThreshold(&mThreshold);
-        }
-    }
-
-    for (auto& graph : mListGraphRtcp)
-    {
-        if (graph != nullptr && graph->getState() == kStreamStateRunning)
-        {
-            graph->setMediaQualityThreshold(&mThreshold);
-        }
-    }
-
     if (mMediaQualityAnalyzer != nullptr)
     {
-        mMediaQualityAnalyzer->setJitterThreshold(
-                mThreshold.getJitterDurationMillis() / 1000,  // milliseconds to seconds
-                mThreshold.getRtpJitterMillis());
-        mMediaQualityAnalyzer->setPacketLossThreshold(
-                mThreshold.getRtpPacketLossDurationMillis() / 1000,  // milliseconds to seconds
-                mThreshold.getRtpPacketLossRate());
+        mMediaQualityAnalyzer->setMediaQualityThreshold(threshold);
     }
 }
 
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtcp.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtcp.cpp
index 09b0e06..e238f06 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtcp.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtcp.cpp
@@ -138,23 +138,6 @@
     return ret;
 }
 
-bool AudioStreamGraphRtcp::setMediaQualityThreshold(MediaQualityThreshold* threshold)
-{
-    if (threshold != nullptr)
-    {
-        BaseNode* node = findNode(kNodeIdRtcpDecoder);
-
-        if (node != nullptr)
-        {
-            RtcpDecoderNode* decoder = reinterpret_cast<RtcpDecoderNode*>(node);
-            decoder->SetInactivityTimerSec(threshold->getRtcpInactivityTimerMillis() / 1000);
-            return true;
-        }
-    }
-
-    return false;
-}
-
 bool AudioStreamGraphRtcp::OnEvent(int32_t type, uint64_t param1, uint64_t param2)
 {
     IMLOGI3("[onEvent] type[%d], param1[%d], param2[%d]", type, param1, param2);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRx.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRx.cpp
index 016d124..d3d0d79 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRx.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRx.cpp
@@ -144,21 +144,4 @@
     }
 
     return ret;
-}
-
-bool AudioStreamGraphRtpRx::setMediaQualityThreshold(MediaQualityThreshold* threshold)
-{
-    if (threshold != nullptr)
-    {
-        BaseNode* node = findNode(kNodeIdRtpDecoder);
-
-        if (node != nullptr)
-        {
-            RtpDecoderNode* decoder = reinterpret_cast<RtpDecoderNode*>(node);
-            decoder->SetInactivityTimerSec(threshold->getRtpInactivityTimerMillis() / 1000);
-            return true;
-        }
-    }
-
-    return false;
 }
\ No newline at end of file
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzer.cpp
index b89c740..460fff1 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzer.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzer.cpp
@@ -23,15 +23,16 @@
 #include <RtcpXrEncoder.h>
 #include <AudioConfig.h>
 #include <stdlib.h>
+#include <algorithm>
 
-#define DEFAULT_PARAM                (-1)
-#define DEFAULT_INACTIVITY_TIME      (5)
-#define CALL_QUALITY_MONITORING_TIME (5)
-#define MAX_NUM_PACKET_STORED        (500)
-#define DELETE_ALL                   (65536)
-#define TIMER_INTERVAL               (1000)   // 1 sec
-#define STOP_TIMEOUT                 (1000)   // 1 sec
-#define MESSAGE_PROCESSING_INTERVAL  (20000)  // 20 msec
+#define DEFAULT_PARAM                            (-1)
+#define DEFAULT_INACTIVITY_TIME_FOR_CALL_QUALITY (4)
+#define CALL_QUALITY_MONITORING_TIME             (5)
+#define MAX_NUM_PACKET_STORED                    (500)
+#define DELETE_ALL                               (65536)
+#define TIMER_INTERVAL                           (1000)   // 1 sec
+#define STOP_TIMEOUT                             (1000)   // 1 sec
+#define MESSAGE_PROCESSING_INTERVAL              (20000)  // 20 msec
 
 MediaQualityAnalyzer::MediaQualityAnalyzer()
 {
@@ -40,10 +41,16 @@
     mCallback = nullptr;
     std::unique_ptr<RtcpXrEncoder> analyzer(new RtcpXrEncoder());
     mRtcpXrEncoder = std::move(analyzer);
-    mJitterThreshold = 0;
-    mJitterDuration = 0;
-    mPacketLossThreshold = 0;
+    mBaseRtpInactivityTimes.clear();
+    mCurrentRtpInactivityTimes.clear();
+    mRtcpInactivityTime = 0;
+    mRtpHysteresisTime = 0;
     mPacketLossDuration = 0;
+    mPacketLossThreshold.clear();
+    mJitterThreshold.clear();
+    mNotifyStatus = false;
+    mCountRtpInactivity = 0;
+    mCountRtcpInactivity = 0;
     reset();
 }
 
@@ -77,25 +84,25 @@
     mCallback = callback;
 }
 
-void MediaQualityAnalyzer::setJitterThreshold(const int32_t duration, const int32_t threshold)
+void MediaQualityAnalyzer::setMediaQualityThreshold(const MediaQualityThreshold& threshold)
 {
-    IMLOGD2("[setJitterThreshold] duration[%d], threshold[%d]", duration, threshold);
-    mJitterThreshold = threshold;
-    mJitterDuration = duration;
+    mBaseRtpInactivityTimes = threshold.getRtpInactivityTimerMillis();
+    mCurrentRtpInactivityTimes = mBaseRtpInactivityTimes;
+    mRtcpInactivityTime = threshold.getRtcpInactivityTimerMillis();
+    mRtpHysteresisTime = threshold.getRtpHysteresisTimeInMillis();
+    mPacketLossDuration = threshold.getRtpPacketLossDurationMillis();
+    mPacketLossThreshold = threshold.getRtpPacketLossRate();
+    mJitterThreshold = threshold.getRtpJitterMillis();
+    mNotifyStatus = threshold.getNotifyCurrentStatus();
 
-    // reset the counter
-    mJitterRxPacket = 0;
-}
+    mCountRtpInactivity = 0;
+    mCountRtcpInactivity = 0;
 
-void MediaQualityAnalyzer::setPacketLossThreshold(const int32_t duration, const int32_t threshold)
-{
-    IMLOGD2("[setPacketLossThreshold] duration[%d], threshold[%d]", duration, threshold);
-    mPacketLossThreshold = threshold;
-    mPacketLossDuration = duration;
+    // reset the status
+    mQualityStatus = MediaQualityStatus();
 
-    // reset the counter
-    mNumRxPacket = 0;
-    mNumLostPacket = 0;
+    mPacketLossChecker.initialize(mRtpHysteresisTime);
+    mJitterChecker.initialize(mRtpHysteresisTime);
 }
 
 bool MediaQualityAnalyzer::isSameConfig(AudioConfig* config)
@@ -107,7 +114,7 @@
 void MediaQualityAnalyzer::start()
 {
     IMLOGD0("[start]");
-    mMediaQuality.setCodecType(convertAudioCodecType(
+    mCallQuality.setCodecType(convertAudioCodecType(
             mCodecType, ImsMediaAudioUtil::FindMaxEvsBandwidthFromRange(mCodecAttribute)));
 
     StartThread();
@@ -124,7 +131,8 @@
 
         if (mCallback != nullptr)
         {
-            MediaQuality* quality = new MediaQuality(mMediaQuality);
+            IMLOGD0("[notifyCallQuality]");
+            CallQuality* quality = new CallQuality(mCallQuality);
             mCallback->SendEvent(kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(quality));
         }
     }
@@ -150,7 +158,7 @@
             delete pPacket;
         }
 
-        mMediaQuality.setNumRtpPacketsTransmitted(mMediaQuality.getNumRtpPacketsTransmitted() + 1);
+        mCallQuality.setNumRtpPacketsTransmitted(mCallQuality.getNumRtpPacketsTransmitted() + 1);
         IMLOGD_PACKET1(IM_PACKET_LOG_RTP, "[collectInfo] tx list size[%d]", mListTxPacket.size());
     }
     else if (streamType == kStreamRtpRx)
@@ -161,25 +169,25 @@
         }
 
         // for call qualty report
-        mMediaQuality.setNumRtpPacketsReceived(mMediaQuality.getNumRtpPacketsReceived() + 1);
+        mCallQuality.setNumRtpPacketsReceived(mCallQuality.getNumRtpPacketsReceived() + 1);
         mCallQualitySumRelativeJitter += packet->jitter;
 
-        if (mMediaQuality.getMaxRelativeJitter() < packet->jitter)
+        if (mCallQuality.getMaxRelativeJitter() < packet->jitter)
         {
-            mMediaQuality.setMaxRelativeJitter(packet->jitter);
+            mCallQuality.setMaxRelativeJitter(packet->jitter);
         }
 
-        mMediaQuality.setAverageRelativeJitter(
-                mCallQualitySumRelativeJitter / mMediaQuality.getNumRtpPacketsReceived());
+        mCallQuality.setAverageRelativeJitter(
+                mCallQualitySumRelativeJitter / mCallQuality.getNumRtpPacketsReceived());
 
         switch (packet->rtpDataType)
         {
             case kRtpDataTypeNoData:
-                mMediaQuality.setNumNoDataFrames(mMediaQuality.getNumNoDataFrames() + 1);
+                mCallQuality.setNumNoDataFrames(mCallQuality.getNumNoDataFrames() + 1);
                 break;
             case kRtpDataTypeSid:
-                mMediaQuality.setNumRtpSidPacketsReceived(
-                        mMediaQuality.getNumRtpSidPacketsReceived() + 1);
+                mCallQuality.setNumRtpSidPacketsReceived(
+                        mCallQuality.getNumRtpSidPacketsReceived() + 1);
                 break;
             default:
             case kRtpDataTypeNormal:
@@ -215,7 +223,7 @@
     }
     else if (streamType == kStreamRtcp)
     {
-        /** TODO: add implementation later */
+        mNumRtcpPacketReceived++;
     }
 }
 
@@ -233,13 +241,13 @@
     {
         mSumRoundTripTime += value;
         mCountRoundTripTime++;
-        mMediaQuality.setAverageRoundTripTime(mSumRoundTripTime / mCountRoundTripTime);
+        mCallQuality.setAverageRoundTripTime(mSumRoundTripTime / mCountRoundTripTime);
 
         mRtcpXrEncoder->setRoundTripDelay(value);
     }
     else if (optionType == kReportPacketLossGap)
     {
-        LostPktEntry* entry = new LostPktEntry(seq, value);
+        LostPacket* entry = new LostPacket(seq, value, ImsMediaTimer::GetTimeInMilliSeconds());
         mListLostPacket.push_back(entry);
 
         for (int32_t i = 0; i < value; i++)
@@ -248,8 +256,8 @@
             mRtcpXrEncoder->stackRxRtpStatus(kRtpStatusLost, 0);
 
             // for call quality report
-            mMediaQuality.setNumRtpPacketsNotReceived(
-                    mMediaQuality.getNumRtpPacketsNotReceived() + 1);
+            mCallQuality.setNumRtpPacketsNotReceived(
+                    mCallQuality.getNumRtpPacketsNotReceived() + 1);
             mCallQualityNumLostPacket++;
             // for loss checking
             mNumLostPacket++;
@@ -279,10 +287,10 @@
         if (packet->seqNum == seq)
         {
             packet->status = status;
-            packet->delay = time - packet->delay;
-            mRtcpXrEncoder->stackRxRtpStatus(packet->status, packet->delay);
+            uint32_t delay = time - packet->arrival;
+            mRtcpXrEncoder->stackRxRtpStatus(packet->status, delay);
             IMLOGD_PACKET3(IM_PACKET_LOG_RTP, "[collectRxRtpStatus] seq[%d], status[%d], delay[%u]",
-                    seq, packet->status, packet->delay);
+                    seq, packet->status, delay);
             found = true;
             break;
         }
@@ -297,16 +305,16 @@
     switch (status)
     {
         case kRtpStatusNormal:
-            mMediaQuality.setNumVoiceFrames(mMediaQuality.getNumVoiceFrames() + 1);
+            mCallQuality.setNumVoiceFrames(mCallQuality.getNumVoiceFrames() + 1);
             mCallQualityNumRxPacket++;
             break;
         case kRtpStatusLate:
         case kRtpStatusDiscarded:
-            mMediaQuality.setNumDroppedRtpPackets(mMediaQuality.getNumDroppedRtpPackets() + 1);
+            mCallQuality.setNumDroppedRtpPackets(mCallQuality.getNumDroppedRtpPackets() + 1);
             mCallQualityNumRxPacket++;
             break;
         case kRtpStatusDuplicated:
-            mMediaQuality.setNumRtpDuplicatePackets(mMediaQuality.getNumRtpDuplicatePackets() + 1);
+            mCallQuality.setNumRtpDuplicatePackets(mCallQuality.getNumRtpDuplicatePackets() + 1);
             mCallQualityNumRxPacket++;
             break;
         default:
@@ -342,20 +350,24 @@
 {
     IMLOGD_PACKET1(IM_PACKET_LOG_RTP, "[processData] count[%d]", timeCount);
 
-    if (timeCount == DEFAULT_INACTIVITY_TIME && mMediaQuality.getNumRtpPacketsReceived() == 0)
+    // call quality inactivity
+    if (timeCount == DEFAULT_INACTIVITY_TIME_FOR_CALL_QUALITY &&
+            mCallQuality.getNumRtpPacketsReceived() == 0)
     {
-        mMediaQuality.setRtpInactivityDetected(true);
+        mCallQuality.setRtpInactivityDetected(true);
 
         if (mCallback != nullptr)
         {
-            MediaQuality* mediaQuality = new MediaQuality(mMediaQuality);
+            IMLOGD0("[notifyCallQuality]");
+            CallQuality* callQuality = new CallQuality(mCallQuality);
             mCallback->SendEvent(
-                    kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(mediaQuality));
+                    kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(callQuality));
         }
     }
 
-    mMediaQuality.setCallDuration(mMediaQuality.getCallDuration() + TIMER_INTERVAL);
+    mCallQuality.setCallDuration(mCallQuality.getCallDuration() + TIMER_INTERVAL);
 
+    // call quality packet loss
     if (timeCount % CALL_QUALITY_MONITORING_TIME == 0)
     {
         double lossRate = 0;
@@ -369,15 +381,16 @@
         IMLOGD3("[processData] lost[%d], received[%d], quality[%d]", mCallQualityNumLostPacket,
                 mCallQualityNumRxPacket, quality);
 
-        if (mMediaQuality.getDownlinkCallQualityLevel() != quality)
+        if (mCallQuality.getDownlinkCallQualityLevel() != quality)
         {
-            mMediaQuality.setDownlinkCallQualityLevel(quality);
+            mCallQuality.setDownlinkCallQualityLevel(quality);
 
             if (mCallback != nullptr)
             {
-                MediaQuality* mediaQuality = new MediaQuality(mMediaQuality);
+                IMLOGD0("[notifyCallQuality]");
+                CallQuality* callQuality = new CallQuality(mCallQuality);
                 mCallback->SendEvent(
-                        kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(mediaQuality));
+                        kAudioCallQualityChangedInd, reinterpret_cast<uint64_t>(callQuality));
             }
         }
 
@@ -385,37 +398,141 @@
         mCallQualityNumRxPacket = 0;
     }
 
-    // check packet loss
-    if (mPacketLossDuration != 0 && (timeCount % mPacketLossDuration) == 0)
+    processMediaQuality();
+}
+
+void MediaQualityAnalyzer::processMediaQuality()
+{
+    // media quality rtp inactivity
+    if (!mCurrentRtpInactivityTimes.empty() && mNumRxPacket == 0)
     {
-        double lossRate = 0;
-
-        if (mNumLostPacket > 0)
-        {
-            lossRate = (double)mNumLostPacket / (mNumRxPacket + mNumLostPacket) * 100;
-        }
-
-        IMLOGD1("[processData] lossRate[%lf]", lossRate);
-
-        if (lossRate >= mPacketLossThreshold && mCallback != nullptr)
-        {
-            mCallback->SendEvent(kImsMediaEventPacketLoss, lossRate);
-        }
-
+        mCountRtpInactivity += 1000;
+    }
+    else
+    {
+        mCountRtpInactivity = 0;
         mNumRxPacket = 0;
-        mNumLostPacket = 0;
+        mCurrentRtpInactivityTimes = mBaseRtpInactivityTimes;
     }
 
-    // check average jitter
-    if (mJitterDuration != 0 && timeCount % mJitterDuration == 0)
+    // media quality rtcp inactivity
+    if (mRtcpInactivityTime != 0 && mNumRtcpPacketReceived == 0)
     {
-        IMLOGD1("[processData] Jitter[%lf]", mJitterRxPacket);
+        mCountRtcpInactivity += 1000;
+    }
+    else
+    {
+        mCountRtcpInactivity = 0;
+        mNumRtcpPacketReceived = 0;
+    }
 
-        if (mJitterRxPacket >= mJitterThreshold && mCallback != nullptr)
+    mQualityStatus.setRtpInactivityTimeMillis(mCountRtpInactivity);
+    mQualityStatus.setRtcpInactivityTimeMillis(mCountRtcpInactivity);
+    mQualityStatus.setRtpJitterMillis(mJitterRxPacket);
+
+    if (mPacketLossDuration != 0 && !mListLostPacket.empty())
+    {
+        // calculate loss in duration
+        int32_t numReceivedPacketsInDuration =
+                std::count_if(mListRxPacket.begin(), mListRxPacket.end(),
+                        [=](RtpPacket* packet)
+                        {
+                            return (ImsMediaTimer::GetTimeInMilliSeconds() - packet->arrival <=
+                                    mPacketLossDuration);
+                        });
+
+        int32_t numLostPacketsInDuration =
+                std::count_if(mListLostPacket.begin(), mListLostPacket.end(),
+                        [=](LostPacket* packet)
+                        {
+                            return (ImsMediaTimer::GetTimeInMilliSeconds() - packet->markedTime <=
+                                    mPacketLossDuration);
+                        });
+
+        if (numLostPacketsInDuration == 0 || numReceivedPacketsInDuration == 0)
         {
-            mCallback->SendEvent(kImsMediaEventNotifyJitter, mJitterRxPacket);
+            mQualityStatus.setRtpPacketLossRate(0);
+        }
+        else
+        {
+            int32_t lossRate = numLostPacketsInDuration * 100 /
+                    (numReceivedPacketsInDuration + numLostPacketsInDuration);
+
+            IMLOGD3("[processData] mediaQualtyStatus lossRate[%d], received[%d], lost[%d]",
+                    lossRate, numReceivedPacketsInDuration, numLostPacketsInDuration);
+            mQualityStatus.setRtpPacketLossRate(lossRate);
         }
     }
+    else
+    {
+        mQualityStatus.setRtpPacketLossRate(0);
+    }
+
+    IMLOGD_PACKET4(IM_PACKET_LOG_RTP,
+            "[processMediaQuality] rtpInactivity[%d], rtcpInactivity[%d], lossRate[%d], "
+            "jitter[%d]",
+            mQualityStatus.getRtpInactivityTimeMillis(),
+            mQualityStatus.getRtcpInactivityTimeMillis(), mQualityStatus.getRtpPacketLossRate(),
+            mQualityStatus.getRtpJitterMillis());
+
+    if (mNotifyStatus)
+    {
+        notifyMediaQualityStatus();
+        mNotifyStatus = false;
+        return;
+    }
+
+    if (!mCurrentRtpInactivityTimes.empty())
+    {
+        std::vector<int32_t>::iterator rtpIter =
+                std::find_if(mCurrentRtpInactivityTimes.begin(), mCurrentRtpInactivityTimes.end(),
+                        [=](int32_t i)
+                        {
+                            return (mCountRtpInactivity >= i);  // check cross the threshold
+                        });
+
+        if (rtpIter != mCurrentRtpInactivityTimes.end())  // found
+        {
+            mCurrentRtpInactivityTimes.erase(rtpIter);
+            notifyMediaQualityStatus();
+            return;
+        }
+    }
+
+    if (mRtcpInactivityTime != 0 && mCountRtcpInactivity >= mRtcpInactivityTime)
+    {
+        notifyMediaQualityStatus();
+        mCountRtcpInactivity = 0;  // reset
+        return;
+    }
+
+    // check jitter notification
+    if (!mJitterThreshold.empty())
+    {
+        if (mJitterChecker.checkNotifiable(mJitterThreshold, mQualityStatus.getRtpJitterMillis()))
+        {
+            notifyMediaQualityStatus();
+            return;
+        }
+    }
+
+    // check packet loss notification
+    if (!mPacketLossThreshold.empty())
+    {
+        if (mPacketLossChecker.checkNotifiable(
+                    mPacketLossThreshold, mQualityStatus.getRtpPacketLossRate()))
+        {
+            notifyMediaQualityStatus();
+            return;
+        }
+    }
+}
+
+void MediaQualityAnalyzer::notifyMediaQualityStatus()
+{
+    IMLOGD0("[notifyMediaQualityStatus]");
+    MediaQualityStatus* status = new MediaQualityStatus(mQualityStatus);
+    mCallback->SendEvent(kImsMediaEventMediaQualityStatus, reinterpret_cast<uint64_t>(status));
 }
 
 bool MediaQualityAnalyzer::getRtcpXrReportBlock(
@@ -442,9 +559,9 @@
     return true;
 }
 
-MediaQuality MediaQualityAnalyzer::getMediaQuality()
+CallQuality MediaQualityAnalyzer::getCallQuality()
 {
-    return mMediaQuality;
+    return mCallQuality;
 }
 
 uint32_t MediaQualityAnalyzer::getRxPacketSize()
@@ -600,7 +717,7 @@
     mBeginSeq = -1;
     mEndSeq = -1;
 
-    mMediaQuality = MediaQuality();
+    mCallQuality = CallQuality();
     mCallQualitySumRelativeJitter = 0;
     mSumRoundTripTime = 0;
     mCountRoundTripTime = 0;
@@ -645,10 +762,10 @@
         return;
     }
 
-    for (std::list<LostPktEntry*>::iterator iter = mListLostPacket.begin();
+    for (std::list<LostPacket*>::iterator iter = mListLostPacket.begin();
             iter != mListLostPacket.end();)
     {
-        LostPktEntry* packet = *iter;
+        LostPacket* packet = *iter;
         // do not remove the lost packet entry seq is larger than target seq
         if (packet->seqNum > seq)
         {
@@ -665,23 +782,23 @@
 {
     if (lossRate < 1.0f)
     {
-        return MediaQuality::kCallQualityExcellent;
+        return CallQuality::kCallQualityExcellent;
     }
     else if (lossRate < 3.0f)
     {
-        return MediaQuality::kCallQualityGood;
+        return CallQuality::kCallQualityGood;
     }
     else if (lossRate < 5.0f)
     {
-        return MediaQuality::kCallQualityFair;
+        return CallQuality::kCallQualityFair;
     }
     else if (lossRate < 8.0f)
     {
-        return MediaQuality::kCallQualityPoor;
+        return CallQuality::kCallQualityPoor;
     }
     else
     {
-        return MediaQuality::kCallQualityBad;
+        return CallQuality::kCallQualityBad;
     }
 }
 
@@ -690,11 +807,11 @@
     switch (codec)
     {
         default:
-            return MediaQuality::AUDIO_QUALITY_NONE;
+            return CallQuality::AUDIO_QUALITY_NONE;
         case AudioConfig::CODEC_AMR:
-            return MediaQuality::AUDIO_QUALITY_AMR;
+            return CallQuality::AUDIO_QUALITY_AMR;
         case AudioConfig::CODEC_AMR_WB:
-            return MediaQuality::AUDIO_QUALITY_AMR_WB;
+            return CallQuality::AUDIO_QUALITY_AMR_WB;
         case AudioConfig::CODEC_EVS:
         {
             switch (bandwidth)
@@ -703,16 +820,16 @@
                 case EvsParams::EVS_BAND_NONE:
                     break;
                 case EvsParams::EVS_NARROW_BAND:
-                    return MediaQuality::AUDIO_QUALITY_EVS_NB;
+                    return CallQuality::AUDIO_QUALITY_EVS_NB;
                 case EvsParams::EVS_WIDE_BAND:
-                    return MediaQuality::AUDIO_QUALITY_EVS_WB;
+                    return CallQuality::AUDIO_QUALITY_EVS_WB;
                 case EvsParams::EVS_SUPER_WIDE_BAND:
-                    return MediaQuality::AUDIO_QUALITY_EVS_SWB;
+                    return CallQuality::AUDIO_QUALITY_EVS_SWB;
                 case EvsParams::EVS_FULL_BAND:
-                    return MediaQuality::AUDIO_QUALITY_EVS_FB;
+                    return CallQuality::AUDIO_QUALITY_EVS_FB;
             }
         }
     }
 
-    return MediaQuality::AUDIO_QUALITY_NONE;
+    return CallQuality::AUDIO_QUALITY_NONE;
 }
\ No newline at end of file
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/RtcpXrEncoder.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/RtcpXrEncoder.cpp
index a8f01ba..d30ea33 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/RtcpXrEncoder.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/RtcpXrEncoder.cpp
@@ -137,7 +137,7 @@
 }
 
 bool RtcpXrEncoder::createRtcpXrReport(const uint32_t rtcpXrReport, std::list<RtpPacket*>* packets,
-        std::list<LostPktEntry*>* lostPackets, uint16_t beginSeq, uint16_t endSeq, uint8_t* data,
+        std::list<LostPacket*>* lostPackets, uint16_t beginSeq, uint16_t endSeq, uint8_t* data,
         uint32_t& size)
 {
     size = 0;
@@ -200,7 +200,7 @@
 }
 
 tLossReport* RtcpXrEncoder::createLossAnalysisReport(std::list<RtpPacket*>* packets,
-        std::list<LostPktEntry*>* lostPackets, uint16_t beginSeq, uint16_t endSeq)
+        std::list<LostPacket*>* lostPackets, uint16_t beginSeq, uint16_t endSeq)
 {
     tLossReport* report = new tLossReport();
     report->beginSeq = beginSeq;
@@ -220,7 +220,7 @@
     {
         if (packet->seqNum >= beginSeq && packet->seqNum <= endSeq)
         {
-            for (int32_t i = 0; i < packet->param1; i++)
+            for (int32_t i = 0; i < packet->numLoss; i++)
             {
                 if (packet->seqNum + i > endSeq)
                 {
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/BaseStreamGraph.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/BaseStreamGraph.h
index c7b18e0..34447da 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/BaseStreamGraph.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/BaseStreamGraph.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef BASE_SESSION_LISTENER_H
-#define BASE_SESSION_LISTENER_H
+#ifndef BASE_STREAM_GRAPH_H
+#define BASE_STREAM_GRAPH_H
 
 #include <ImsMediaDefine.h>
 #include <StreamScheduler.h>
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h
index bc657e1..7469970 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h
@@ -50,9 +50,8 @@
     kImsMediaEventStateChanged,
     kImsMediaEventFirstPacketReceived,
     kImsMediaEventHeaderExtensionReceived,
+    kImsMediaEventMediaQualityStatus,
     kImsMediaEventMediaInactivity,
-    kImsMediaEventPacketLoss,
-    kImsMediaEventNotifyJitter,
     kImsMediaEventResolutionChanged,
     kImsMediaEventNotifyVideoDataUsage,
     kImsMediaEventNotifyRttReceived,
@@ -307,9 +306,7 @@
     kAudioConfirmConfigResponse,
     kAudioFirstMediaPacketInd,
     kAudioRtpHeaderExtensionInd,
-    kAudioMediaInactivityInd,
-    kAudioPacketLossInd,
-    kAudioJitterInd,
+    kAudioMediaQualityStatusInd,
     kAudioTriggerAnbrQueryInd,
     kAudioDtmfReceivedInd,
     kAudioCallQualityChangedInd,
@@ -489,6 +486,7 @@
     kReportPacketLossGap,
 };
 
+/** TODO: change the name to avoid confusion by similarity */
 struct RtpPacket
 {
 public:
@@ -497,7 +495,7 @@
             seqNum(0),
             TTL(0),
             jitter(0),
-            delay(0),
+            arrival(0),
             rtpDataType(kRtpDataTypeNoData),
             status(kRtpStatusNotDefined)
     {
@@ -508,26 +506,18 @@
         seqNum = p.seqNum;
         TTL = p.TTL;
         jitter = p.jitter;
+        arrival = p.arrival;
         rtpDataType = p.rtpDataType;
         status = p.status;
     }
-    RtpPacket(const RtpPacket* p)
-    {
-        ssrc = p->ssrc;
-        seqNum = p->seqNum;
-        TTL = p->TTL;
-        jitter = p->jitter;
-        rtpDataType = p->rtpDataType;
-        status = p->status;
-    }
 
     uint32_t ssrc;
     uint32_t seqNum;
     uint32_t TTL;
     /** transit time difference */
     int32_t jitter;
-    /** delay from arrival to play */
-    int32_t delay;
+    /** arrival time */
+    int32_t arrival;
     kRtpDataType rtpDataType;
     kRtpPacketStatus status;
 };
@@ -536,18 +526,24 @@
  * @brief It is lost packet data structure to store the start number of packet sequence and the
  * number of lost packets
  */
-struct LostPktEntry
+struct LostPacket
 {
 public:
-    LostPktEntry(uint16_t s = 0, uint32_t p1 = 0, uint32_t p2 = 0) :
+    LostPacket(uint16_t s = 0, uint32_t num = 0, uint32_t time = 0, uint32_t opt = 0) :
             seqNum(s),
-            param1(p1),
-            param2(p2)
+            numLoss(num),
+            markedTime(time),
+            option(opt)
     {
     }
+    /** The rtp sequence number of beginning of lost packet */
     uint16_t seqNum;
-    uint32_t param1;
-    uint32_t param2;
+    /** The number of lost packets */
+    uint32_t numLoss;
+    /** The time in milliseconds when determined to lost */
+    uint32_t markedTime;
+    /** optional parameter for nack */
+    uint32_t option;
 };
 
 struct tRtpHeaderExtensionInfo
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraph.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraph.h
index 8031a3f..203ea68 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraph.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraph.h
@@ -50,9 +50,6 @@
     }
 
 protected:
-    virtual ImsMediaResult create(RtpConfig* config) = 0;
-    virtual ImsMediaResult update(RtpConfig* config) = 0;
-
     AudioConfig* mConfig;
 };
 
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtcp.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtcp.h
index 4c9aac1..9691826 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtcp.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtcp.h
@@ -27,7 +27,6 @@
     virtual ~AudioStreamGraphRtcp();
     virtual ImsMediaResult create(RtpConfig* config);
     virtual ImsMediaResult update(RtpConfig* config);
-    virtual bool setMediaQualityThreshold(MediaQualityThreshold* threshold);
     virtual bool OnEvent(int32_t type, uint64_t param1, uint64_t param2);
 };
 
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpRx.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpRx.h
index ae48f75..cfc9e55 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpRx.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpRx.h
@@ -27,7 +27,6 @@
     virtual ~AudioStreamGraphRtpRx();
     virtual ImsMediaResult create(RtpConfig* config);
     virtual ImsMediaResult update(RtpConfig* config);
-    virtual bool setMediaQualityThreshold(MediaQualityThreshold* threshold);
 };
 
 #endif
\ No newline at end of file
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/MediaQualityAnalyzer.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/MediaQualityAnalyzer.h
index 85f5738..29f0bb4 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/MediaQualityAnalyzer.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/MediaQualityAnalyzer.h
@@ -17,15 +17,96 @@
 #ifndef MEDIA_QUALITY_ANALYZER_H_INCLUDED
 #define MEDIA_QUALITY_ANALYZER_H_INCLUDED
 
-#include <MediaQuality.h>
+#include <CallQuality.h>
 #include <ImsMediaDefine.h>
 #include <IImsMediaThread.h>
 #include <ImsMediaCondition.h>
 #include <RtcpXrEncoder.h>
 #include <BaseSessionCallback.h>
 #include <AudioConfig.h>
+#include <MediaQualityThreshold.h>
+#include <MediaQualityStatus.h>
 #include <list>
+#include <vector>
 #include <mutex>
+#include <algorithm>
+
+class HysteresisTimeChecker
+{
+public:
+    HysteresisTimeChecker(int32_t time = 0)
+    {
+        hysteresisTime = time;
+        countHysteresisTime = hysteresisTime;
+        notifiedDirection = 1;
+        firstNotified = false;
+        previousValue = 0;
+    }
+
+    void initialize(int32_t time)
+    {
+        hysteresisTime = time;
+        countHysteresisTime = hysteresisTime;
+        notifiedDirection = 1;
+        firstNotified = false;
+        previousValue = 0;
+    }
+
+    ~HysteresisTimeChecker() {}
+
+    bool checkNotifiable(std::vector<int32_t> thresholds, int32_t currentValue)
+    {
+        if (thresholds.empty())
+        {
+            return false;
+        }
+
+        bool notifiable = false;
+
+        // cross the threshold case
+        auto iterCrossed = find_if(thresholds.begin(), thresholds.end(),
+                [=](int32_t thres)
+                {
+                    return ((currentValue >= thres && previousValue < thres) ||
+                            (currentValue < thres && previousValue >= thres));
+                });
+
+        if (iterCrossed != thresholds.end())
+        {
+            uint32_t currentDirection = (currentValue - previousValue) > 0 ? 1 : 0;
+
+            if (countHysteresisTime >= hysteresisTime || currentDirection == notifiedDirection)
+            {
+                if (!firstNotified)
+                {
+                    firstNotified = true;
+                }
+
+                previousValue = currentValue;
+                countHysteresisTime = 0;
+                notifiedDirection = currentDirection;
+                notifiable = true;
+            }
+
+            countHysteresisTime++;
+        }
+        else
+        {
+            if (firstNotified)
+            {
+                countHysteresisTime = 1;
+            }
+        }
+
+        return notifiable;
+    }
+
+    int32_t hysteresisTime;
+    int32_t countHysteresisTime;
+    int32_t previousValue;
+    uint32_t notifiedDirection;
+    bool firstNotified;
+};
 
 class MediaQualityAnalyzer : public IImsMediaThread
 {
@@ -45,22 +126,9 @@
     void setConfig(AudioConfig* config);
 
     /**
-     * @brief Set the jitter notification threshold. If the receiving packet jitter exceed
-     * the threshold, notification will be send
-     *
-     * @param duration The monitoring duration in sec unit for jitter
-     * @param threshold The threshold of jitter in milliseconds unit
+     * @brief Set the MediaQualityThreshold
      */
-    void setJitterThreshold(const int32_t duration, const int32_t threshold);
-
-    /**
-     * @brief Set the packet loss notification threshold. If the receiving packet loss rate exceed
-     * the threshold, notification will be send
-     *
-     * @param duration The monitoring duration in sec unit for loss rate
-     * @param threshold The threshold of pakcet loss rate in percentage unit
-     */
-    void setPacketLossThreshold(const int32_t duration, const int32_t threshold);
+    void setMediaQualityThreshold(const MediaQualityThreshold& threshold);
 
     /**
      * @brief Check the audio config has different codec values
@@ -125,9 +193,9 @@
     bool getRtcpXrReportBlock(const uint32_t nReportBlocks, uint8_t* data, uint32_t& size);
 
     /**
-     * @brief Get the MediaQuality member instance
+     * @brief Get the CallQuality member instance
      */
-    MediaQuality getMediaQuality();
+    CallQuality getCallQuality();
 
     /**
      * @brief Get number of rx packets in the list
@@ -160,6 +228,8 @@
      * @param timeCount The count increased every second
      */
     void processData(const int32_t timeCount);
+    void processMediaQuality();
+    void notifyMediaQualityStatus();
     void AddEvent(uint32_t event, uint64_t paramA, uint64_t paramB);
     void processEvent(uint32_t event, uint64_t paramA, uint64_t paramB);
     virtual void* run();
@@ -174,7 +244,7 @@
     /** The list of the packets received ordered by arrival time */
     std::list<RtpPacket*> mListRxPacket;
     /** The list of the lost packets object */
-    std::list<LostPktEntry*> mListLostPacket;
+    std::list<LostPacket*> mListLostPacket;
     /** The list of the packets sent */
     std::list<RtpPacket*> mListTxPacket;
     /** The ssrc of the receiving Rtp stream to identify */
@@ -187,8 +257,8 @@
     int32_t mBeginSeq;
     /** The end of the rx rtp packet sequence number for Rtcp-Xr report */
     int32_t mEndSeq;
-    /** The media quality structure to report */
-    MediaQuality mMediaQuality;
+    /** The call quality structure to report */
+    CallQuality mCallQuality;
     /** The sum of the relative jitter of rx packet for call quality */
     int64_t mCallQualitySumRelativeJitter;
     /** The sum of the round trip delay of the session for call quality */
@@ -203,21 +273,37 @@
     uint32_t mCallQualityNumRxPacket;
     /** The number of lost rx packet for call quality calculation */
     uint32_t mCallQualityNumLostPacket;
-    /** The jitter threshold to check */
-    int32_t mJitterThreshold;
-    /** The monitoring time to check jitter threshold in sec unit */
-    int32_t mJitterDuration;
-    /** The packet loss rate threshold in percentage unit */
-    int32_t mPacketLossThreshold;
-    /** The monitoring time of packet loss rate in sec unit */
+
+    // MediaQualityThreshold parameters
+    std::vector<int32_t> mBaseRtpInactivityTimes;
+    std::vector<int32_t> mCurrentRtpInactivityTimes;
+    int32_t mRtcpInactivityTime;
+    int32_t mRtpHysteresisTime;
     int32_t mPacketLossDuration;
+    std::vector<int32_t> mPacketLossThreshold;
+    std::vector<int32_t> mJitterThreshold;
+    bool mNotifyStatus;
+
+    // Counter for inactivity check
+    int32_t mCountRtpInactivity;
+    int32_t mCountRtcpInactivity;
+
+    /** The MediaQualityStatus structure to report */
+    MediaQualityStatus mQualityStatus;
+
     /** The number of received packet to check packet loss notification */
     uint32_t mNumRxPacket;
     /** The number of lost packet to check packet loss notification */
     uint32_t mNumLostPacket;
     /** The cumulated jitter value when any rx packet received */
     double mJitterRxPacket;
+    /** The number of rtcp packet received */
+    uint32_t mNumRtcpPacketReceived;
 
+    HysteresisTimeChecker mPacketLossChecker;
+    HysteresisTimeChecker mJitterChecker;
+
+    // event parameters
     std::list<uint32_t> mListevent;
     std::list<uint64_t> mListParamA;
     std::list<uint64_t> mListParamB;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/RtcpXrEncoder.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/RtcpXrEncoder.h
index f415a6d..0ce6842 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/RtcpXrEncoder.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/RtcpXrEncoder.h
@@ -198,12 +198,12 @@
      * @return false The bitmask of the report block types are zero or data buffer is null
      */
     bool createRtcpXrReport(const uint32_t nRtcpXrReport, std::list<RtpPacket*>* packets,
-            std::list<LostPktEntry*>* lostPackets, uint16_t beginSeq, uint16_t endSeq,
-            uint8_t* data, uint32_t& size);
+            std::list<LostPacket*>* lostPackets, uint16_t beginSeq, uint16_t endSeq, uint8_t* data,
+            uint32_t& size);
 
 private:
     tLossReport* createLossAnalysisReport(std::list<RtpPacket*>* packets,
-            std::list<LostPktEntry*>* lostPackets, uint16_t beginSeq, uint16_t endSeq);
+            std::list<LostPacket*>* lostPackets, uint16_t beginSeq, uint16_t endSeq);
     tJitterReport* createJitterAnalysisReport(
             std::list<RtpPacket*>* packets, uint16_t beginSeq, uint16_t endSeq);
     tTTLReport* createTTLAnalysisReport(
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoJitterBuffer.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoJitterBuffer.h
index 3316f85..9319e3f 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoJitterBuffer.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoJitterBuffer.h
@@ -90,7 +90,7 @@
     void CheckPacketLoss(uint16_t seqNum, uint16_t nLastRecvPkt);
     bool UpdateLostPacketList(uint16_t mLossRateThreshold, uint16_t* countSecondNack,
             uint16_t* nPLIPkt, bool* bPLIPkt);
-    bool UpdateNackStatus(LostPktEntry* pTempEntry, uint16_t mLossRateThreshold,
+    bool UpdateNackStatus(LostPacket* pTempEntry, uint16_t mLossRateThreshold,
             uint16_t* countSecondNack, uint16_t* nPLIPkt, bool* bPLIPkt);
     void RequestSendNack(
             uint16_t nLossGap, uint16_t PID, uint16_t countSecondNack, bool bNACK = true);
@@ -113,7 +113,7 @@
     uint32_t mLastAddedTimestamp;
     uint32_t mLastAddedSeqNum;
     uint32_t mResponseWaitTime;
-    std::list<LostPktEntry*> mLostPktList;
+    std::list<LostPacket*> mLostPktList;
     uint32_t mIDRCheckCnt;
     uint32_t mFirTimeStamp;
     uint32_t mMaxBitrate;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoStreamGraph.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoStreamGraph.h
index aef426f..3e14559 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoStreamGraph.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoStreamGraph.h
@@ -50,12 +50,7 @@
                 mConfig->getRemotePort() == config->getRemotePort());
     }
 
-    virtual bool OnEvent(int32_t type, uint64_t param1, uint64_t param2) = 0;
-
 protected:
-    virtual ImsMediaResult create(RtpConfig* config) = 0;
-    virtual ImsMediaResult update(RtpConfig* config) = 0;
-
     VideoConfig* mConfig;
 };
 
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNode.cpp
index 863b44f..7682bfc 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNode.cpp
@@ -137,6 +137,11 @@
             tNotifyReceiveRtcpSrInd* payload = reinterpret_cast<tNotifyReceiveRtcpSrInd*>(data);
             IMLOGD_PACKET2(IM_PACKET_LOG_RTCP, "[OnRtcpInd] RtcpSr - fractionLost[%d], jitter[%d]",
                     payload->stRecvRpt.fractionLost, payload->stRecvRpt.jitter);
+
+            if (mMediaType == IMS_MEDIA_AUDIO)
+            {
+                mCallback->SendEvent(kCollectPacketInfo, kStreamRtcp);
+            }
         }
         break;
         case RTPSVC_RECEIVE_RTCP_RR_IND:
@@ -144,6 +149,11 @@
             tNotifyReceiveRtcpRrInd* payload = reinterpret_cast<tNotifyReceiveRtcpRrInd*>(data);
             IMLOGD_PACKET2(IM_PACKET_LOG_RTCP, "[OnRtcpInd] RtcpRr - fractionLost[%d], jitter[%d]",
                     payload->stRecvRpt.fractionLost, payload->stRecvRpt.jitter);
+
+            if (mMediaType == IMS_MEDIA_AUDIO)
+            {
+                mCallback->SendEvent(kCollectPacketInfo, kStreamRtcp);
+            }
         }
         break;
         case RTPSVC_RECEIVE_RTCP_FB_IND:
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpRx.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpRx.cpp
index 7897d8e..fa7eafa 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpRx.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpRx.cpp
@@ -199,7 +199,9 @@
         if (node != nullptr)
         {
             RtpDecoderNode* decoder = reinterpret_cast<RtpDecoderNode*>(node);
-            decoder->SetInactivityTimerSec(threshold->getRtpInactivityTimerMillis() / 1000);
+            decoder->SetInactivityTimerSec(threshold->getRtpInactivityTimerMillis().empty()
+                            ? 0
+                            : threshold->getRtpInactivityTimerMillis().front() / 1000);
             return true;
         }
     }
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoJitterBuffer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoJitterBuffer.cpp
index 1df5aa1..a80f1b6 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoJitterBuffer.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoJitterBuffer.cpp
@@ -106,7 +106,7 @@
 
     while (!mLostPktList.empty())
     {
-        LostPktEntry* entry = mLostPktList.front();
+        LostPacket* entry = mLostPktList.front();
 
         if (entry != nullptr)
         {
@@ -687,8 +687,8 @@
 
 void VideoJitterBuffer::RemovePacketFromLostList(uint16_t seqNum, bool bRemoveOldPacket)
 {
-    LostPktEntry* pEntry = nullptr;
-    std::list<LostPktEntry*>::iterator it = mLostPktList.begin();
+    LostPacket* pEntry = nullptr;
+    std::list<LostPacket*>::iterator it = mLostPktList.begin();
 
     while (it != mLostPktList.end())
     {
@@ -799,9 +799,9 @@
 bool VideoJitterBuffer::UpdateLostPacketList(
         uint16_t lostSeq, uint16_t* countSecondNack, uint16_t* nPLIPkt, bool* bPLIPkt)
 {
-    LostPktEntry* foundLostPacket = nullptr;
+    LostPacket* foundLostPacket = nullptr;
     auto result = std::find_if(mLostPktList.begin(), mLostPktList.end(),
-            [lostSeq, &foundLostPacket](LostPktEntry* entry)
+            [lostSeq, &foundLostPacket](LostPacket* entry)
             {
                 foundLostPacket = entry;
                 return (entry->seqNum == lostSeq);
@@ -815,33 +815,33 @@
     IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[UpdateLostPacketList] add lost seq[%u], queue size[%d]",
             lostSeq, mLostPktList.size());
 
-    LostPktEntry* entry =
-            new LostPktEntry(lostSeq, ImsMediaTimer::GetTimeInMilliSeconds(), kRequestSendNackNone);
+    LostPacket* entry =
+            new LostPacket(lostSeq, ImsMediaTimer::GetTimeInMilliSeconds(), kRequestSendNackNone);
     mLostPktList.push_back(entry);
     mNumLossPacket++;
     return false;
 }
 
-bool VideoJitterBuffer::UpdateNackStatus(LostPktEntry* pEntry, uint16_t lostSeq,
+bool VideoJitterBuffer::UpdateNackStatus(LostPacket* pEntry, uint16_t lostSeq,
         uint16_t* countSecondNack, uint16_t* nPLIPkt, bool* bPLIPkt)
 {
     /**
      * Send initial NACK if there is error in decoding frame due to packet loss
      */
-    if (pEntry->param2 == kRequestSendNackNone)
+    if (pEntry->option == kRequestSendNackNone)
     {
-        if ((ImsMediaTimer::GetTimeInMilliSeconds() - pEntry->param1) < mFrameInterval)
+        if ((ImsMediaTimer::GetTimeInMilliSeconds() - pEntry->markedTime) < mFrameInterval)
         {
             return false;
         }
 
-        pEntry->param1 = ImsMediaTimer::GetTimeInMilliSeconds();
-        pEntry->param2 = kRequestInitialNack;
+        pEntry->markedTime = ImsMediaTimer::GetTimeInMilliSeconds();
+        pEntry->option = kRequestInitialNack;
         IMLOGD_PACKET1(IM_PACKET_LOG_JITTER, "[UpdateNackStatus] initial NACK, seq[%u]", lostSeq);
         return true;
     }
 
-    if ((ImsMediaTimer::GetTimeInMilliSeconds() - pEntry->param1) < mResponseWaitTime)
+    if ((ImsMediaTimer::GetTimeInMilliSeconds() - pEntry->markedTime) < mResponseWaitTime)
     {
         return false;
     }
@@ -849,29 +849,29 @@
     /**
      * Send Second NACK if there is first packet still not arrived within RWT duration
      */
-    if (pEntry->param2 == kRequestInitialNack)
+    if (pEntry->option == kRequestInitialNack)
     {
         (*countSecondNack)++;
-        pEntry->param1 = ImsMediaTimer::GetTimeInMilliSeconds();
-        pEntry->param2 = kRequestSecondNack;
+        pEntry->markedTime = ImsMediaTimer::GetTimeInMilliSeconds();
+        pEntry->option = kRequestSecondNack;
         IMLOGD_PACKET1(IM_PACKET_LOG_JITTER, "[UpdateNackStatus] second NACK, seq[%u]", lostSeq);
         return true;
     }
-    else if (pEntry->param2 == kRequestSecondNack)
+    else if (pEntry->option == kRequestSecondNack)
     {
         /**
          * Send PLI if the recovery picture does not arrived within two RWT duration
          */
         *nPLIPkt = lostSeq;
         *bPLIPkt = true;
-        pEntry->param1 = ImsMediaTimer::GetTimeInMilliSeconds();
-        pEntry->param2 = kRequestPli;
+        pEntry->markedTime = ImsMediaTimer::GetTimeInMilliSeconds();
+        pEntry->option = kRequestPli;
         IMLOGD_PACKET1(IM_PACKET_LOG_JITTER, "[UpdateNackStatus] request PLI seq[%u]", lostSeq);
     }
-    else if (pEntry->param2 == kRequestPli)
+    else if (pEntry->option == kRequestPli)
     {
         *nPLIPkt = lostSeq;
-        pEntry->param1 = ImsMediaTimer::GetTimeInMilliSeconds();
+        pEntry->markedTime = ImsMediaTimer::GetTimeInMilliSeconds();
     }
 
     return false;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoSession.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoSession.cpp
index 4fdb301..074e37c 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoSession.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoSession.cpp
@@ -261,10 +261,6 @@
             ImsMediaEventHandler::SendEvent(
                     "VIDEO_RESPONSE_EVENT", kVideoMediaInactivityInd, mSessionId, param1, param2);
             break;
-        case kImsMediaEventPacketLoss:
-            ImsMediaEventHandler::SendEvent(
-                    "VIDEO_RESPONSE_EVENT", kVideoPacketLossInd, mSessionId, param1, param2);
-            break;
         case kImsMediaEventNotifyVideoDataUsage:
             ImsMediaEventHandler::SendEvent(
                     "VIDEO_RESPONSE_EVENT", kVideoDataUsageInd, mSessionId, param1, param2);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpRx.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpRx.cpp
index bdee438..c93bf83 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpRx.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpRx.cpp
@@ -213,7 +213,9 @@
         if (node != nullptr)
         {
             RtpDecoderNode* decoder = reinterpret_cast<RtpDecoderNode*>(node);
-            decoder->SetInactivityTimerSec(threshold->getRtpInactivityTimerMillis() / 1000);
+            decoder->SetInactivityTimerSec(threshold->getRtpInactivityTimerMillis().empty()
+                            ? 0
+                            : threshold->getRtpInactivityTimerMillis().front() / 1000);
             return true;
         }
 
@@ -222,8 +224,10 @@
         if (node != nullptr)
         {
             IVideoRendererNode* decoder = reinterpret_cast<IVideoRendererNode*>(node);
-            decoder->SetPacketLossParam(
-                    threshold->getRtpPacketLossDurationMillis(), threshold->getRtpPacketLossRate());
+            decoder->SetPacketLossParam(threshold->getRtpPacketLossDurationMillis(),
+                    threshold->getRtpPacketLossRate().empty()
+                            ? 0
+                            : threshold->getRtpPacketLossRate().front());
             return true;
         }
     }
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/CallQualityTest.cpp
similarity index 94%
rename from tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityTest.cpp
rename to tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/CallQualityTest.cpp
index 796bc28..5fcc6f9 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/CallQualityTest.cpp
@@ -15,7 +15,7 @@
  */
 
 #include <AudioConfig.h>
-#include <MediaQuality.h>
+#include <CallQuality.h>
 #include <gtest/gtest.h>
 
 using namespace android::telephony::imsmedia;
@@ -42,12 +42,12 @@
 const int32_t kNumRtpSidPacketsReceived = 10;
 const int32_t kNumRtpDuplicatePackets = 1;
 
-class MediaQualityTest : public ::testing::Test
+class CallQualityTest : public ::testing::Test
 {
 public:
-    MediaQuality quality1;
-    MediaQuality quality2;
-    MediaQuality quality3;
+    CallQuality quality1;
+    CallQuality quality2;
+    CallQuality quality3;
 
 protected:
     virtual void SetUp() override
@@ -78,26 +78,26 @@
     virtual void TearDown() override {}
 };
 
-TEST_F(MediaQualityTest, TestGetterSetter) {}
+TEST_F(CallQualityTest, TestGetterSetter) {}
 
-TEST_F(MediaQualityTest, TestParcel)
+TEST_F(CallQualityTest, TestParcel)
 {
     android::Parcel parcel;
     quality1.writeToParcel(&parcel);
     parcel.setDataPosition(0);
 
-    MediaQuality testQuality;
+    CallQuality testQuality;
     testQuality.readFromParcel(&parcel);
     EXPECT_EQ(testQuality, quality1);
 }
 
-TEST_F(MediaQualityTest, TestAssign)
+TEST_F(CallQualityTest, TestAssign)
 {
-    MediaQuality testQuality = quality1;
+    CallQuality testQuality = quality1;
     EXPECT_EQ(quality1, testQuality);
 }
 
-TEST_F(MediaQualityTest, TestEqual)
+TEST_F(CallQualityTest, TestEqual)
 {
     quality2.setDownlinkCallQualityLevel(kDownlinkCallQualityLevel);
     quality2.setUplinkCallQualityLevel(kUplinkCallQualityLevel);
@@ -123,7 +123,7 @@
     EXPECT_EQ(quality2, quality1);
 }
 
-TEST_F(MediaQualityTest, TestNotEqual)
+TEST_F(CallQualityTest, TestNotEqual)
 {
     quality2.setDownlinkCallQualityLevel(kDownlinkCallQualityLevel);
     quality2.setUplinkCallQualityLevel(kUplinkCallQualityLevel);
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityStatusTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityStatusTest.cpp
new file mode 100644
index 0000000..c32c2d2
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityStatusTest.cpp
@@ -0,0 +1,95 @@
+/**
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <MediaQualityStatus.h>
+#include <gtest/gtest.h>
+
+using namespace android::telephony::imsmedia;
+
+const int32_t kRtpInactivityTimeMillis = 10000;
+const int32_t kRtcpInactivityTimeMillis = 10000;
+const int32_t kRtpPacketLossRate = 1;
+const int32_t kRtpJitterMillis = 100;
+
+class MediaQualityStatusTest : public ::testing::Test
+{
+public:
+    MediaQualityStatus status;
+
+protected:
+    virtual void SetUp() override
+    {
+        status.setRtpInactivityTimeMillis(kRtpInactivityTimeMillis);
+        status.setRtcpInactivityTimeMillis(kRtcpInactivityTimeMillis);
+        status.setRtpPacketLossRate(kRtpPacketLossRate);
+        status.setRtpJitterMillis(kRtpJitterMillis);
+    }
+
+    virtual void TearDown() override {}
+};
+
+TEST_F(MediaQualityStatusTest, TestGetterSetter)
+{
+    EXPECT_EQ(status.getRtpInactivityTimeMillis(), kRtpInactivityTimeMillis);
+    EXPECT_EQ(status.getRtcpInactivityTimeMillis(), kRtcpInactivityTimeMillis);
+    EXPECT_EQ(status.getRtpPacketLossRate(), kRtpPacketLossRate);
+    EXPECT_EQ(status.getRtpJitterMillis(), kRtpJitterMillis);
+}
+
+TEST_F(MediaQualityStatusTest, TestParcel)
+{
+    android::Parcel parcel;
+    status.writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+
+    MediaQualityStatus testThreshold;
+    testThreshold.readFromParcel(&parcel);
+    EXPECT_EQ(testThreshold, status);
+}
+
+TEST_F(MediaQualityStatusTest, TestAssign)
+{
+    MediaQualityStatus status2 = status;
+    EXPECT_EQ(status, status2);
+}
+
+TEST_F(MediaQualityStatusTest, TestEqual)
+{
+    MediaQualityStatus status2;
+    status2.setRtpInactivityTimeMillis(kRtpInactivityTimeMillis);
+    status2.setRtcpInactivityTimeMillis(kRtcpInactivityTimeMillis);
+    status2.setRtpPacketLossRate(kRtpPacketLossRate);
+    status2.setRtpJitterMillis(kRtpJitterMillis);
+    EXPECT_EQ(status, status2);
+}
+
+TEST_F(MediaQualityStatusTest, TestNotEqual)
+{
+    MediaQualityStatus status2;
+    status2.setRtpInactivityTimeMillis(15000);
+    status2.setRtcpInactivityTimeMillis(kRtcpInactivityTimeMillis);
+    status2.setRtpPacketLossRate(kRtpPacketLossRate);
+    status2.setRtpJitterMillis(kRtpJitterMillis);
+
+    MediaQualityStatus status3;
+    status3.setRtpInactivityTimeMillis(kRtpInactivityTimeMillis);
+    status3.setRtcpInactivityTimeMillis(kRtcpInactivityTimeMillis);
+    status3.setRtpPacketLossRate(3);
+    status3.setRtpJitterMillis(kRtpJitterMillis);
+
+    EXPECT_NE(status, status2);
+    EXPECT_NE(status, status3);
+}
\ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityThresholdTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityThresholdTest.cpp
index c3090a4..1ab1ff0 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityThresholdTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityThresholdTest.cpp
@@ -19,29 +19,29 @@
 
 using namespace android::telephony::imsmedia;
 
-const int32_t kRtpInactivityTimerMillis = 10000;
+const std::vector<int32_t> kRtpInactivityTimerMillis = {10000, 20000};
 const int32_t kRtcpInactivityTimerMillis = 20000;
+const int32_t kRtpHysteresisTimeInMillis = 3000;
 const int32_t kRtpPacketLossDurationMillis = 5000;
-const int32_t kRtpPacketLossRate = 5;
-const int32_t kJitterDurationMillis = 5000;
-const int32_t kRtpJitterMillis = 300;
+const std::vector<int32_t> kRtpPacketLossRate = {3, 5};
+const std::vector<int32_t> kRtpJitterMillis = {100, 200};
+const bool kNotifyCurrentStatus = false;
 
 class MediaQualityThresholdTest : public ::testing::Test
 {
 public:
-    MediaQualityThreshold threshold1;
-    MediaQualityThreshold threshold2;
-    MediaQualityThreshold threshold3;
+    MediaQualityThreshold threshold;
 
 protected:
     virtual void SetUp() override
     {
-        threshold1.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis);
-        threshold1.setRtcpInactivityTimerMillis(kRtcpInactivityTimerMillis);
-        threshold1.setRtpPacketLossDurationMillis(kRtpPacketLossDurationMillis);
-        threshold1.setRtpPacketLossRate(kRtpPacketLossRate);
-        threshold1.setJitterDurationMillis(kJitterDurationMillis);
-        threshold1.setRtpJitterMillis(kRtpJitterMillis);
+        threshold.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis);
+        threshold.setRtcpInactivityTimerMillis(kRtcpInactivityTimerMillis);
+        threshold.setRtpHysteresisTimeInMillis(kRtpHysteresisTimeInMillis);
+        threshold.setRtpPacketLossDurationMillis(kRtpPacketLossDurationMillis);
+        threshold.setRtpPacketLossRate(kRtpPacketLossRate);
+        threshold.setRtpJitterMillis(kRtpJitterMillis);
+        threshold.setNotifyCurrentStatus(kNotifyCurrentStatus);
     }
 
     virtual void TearDown() override {}
@@ -49,59 +49,65 @@
 
 TEST_F(MediaQualityThresholdTest, TestGetterSetter)
 {
-    EXPECT_EQ(threshold1.getRtpInactivityTimerMillis(), kRtpInactivityTimerMillis);
-    EXPECT_EQ(threshold1.getRtcpInactivityTimerMillis(), kRtcpInactivityTimerMillis);
-    EXPECT_EQ(threshold1.getRtpPacketLossDurationMillis(), kRtpPacketLossDurationMillis);
-    EXPECT_EQ(threshold1.getRtpPacketLossRate(), kRtpPacketLossRate);
-    EXPECT_EQ(threshold1.getJitterDurationMillis(), kJitterDurationMillis);
-    EXPECT_EQ(threshold1.getRtpJitterMillis(), kRtpJitterMillis);
+    EXPECT_EQ(threshold.getRtpInactivityTimerMillis(), kRtpInactivityTimerMillis);
+    EXPECT_EQ(threshold.getRtcpInactivityTimerMillis(), kRtcpInactivityTimerMillis);
+    EXPECT_EQ(threshold.getRtpHysteresisTimeInMillis(), kRtpHysteresisTimeInMillis);
+    EXPECT_EQ(threshold.getRtpPacketLossDurationMillis(), kRtpPacketLossDurationMillis);
+    EXPECT_EQ(threshold.getRtpPacketLossRate(), kRtpPacketLossRate);
+    EXPECT_EQ(threshold.getRtpJitterMillis(), kRtpJitterMillis);
+    EXPECT_EQ(threshold.getNotifyCurrentStatus(), kNotifyCurrentStatus);
 }
 
 TEST_F(MediaQualityThresholdTest, TestParcel)
 {
     android::Parcel parcel;
-    threshold1.writeToParcel(&parcel);
+    threshold.writeToParcel(&parcel);
     parcel.setDataPosition(0);
 
     MediaQualityThreshold testThreshold;
     testThreshold.readFromParcel(&parcel);
-    EXPECT_EQ(testThreshold, threshold1);
+    EXPECT_EQ(testThreshold, threshold);
 }
 
 TEST_F(MediaQualityThresholdTest, TestAssign)
 {
-    MediaQualityThreshold threshold2 = threshold1;
-    EXPECT_EQ(threshold1, threshold2);
+    MediaQualityThreshold threshold2 = threshold;
+    EXPECT_EQ(threshold, threshold2);
 }
 
 TEST_F(MediaQualityThresholdTest, TestEqual)
 {
+    MediaQualityThreshold threshold2;
     threshold2.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis);
     threshold2.setRtcpInactivityTimerMillis(kRtcpInactivityTimerMillis);
+    threshold2.setRtpHysteresisTimeInMillis(kRtpHysteresisTimeInMillis);
     threshold2.setRtpPacketLossDurationMillis(kRtpPacketLossDurationMillis);
     threshold2.setRtpPacketLossRate(kRtpPacketLossRate);
-    threshold2.setJitterDurationMillis(kJitterDurationMillis);
     threshold2.setRtpJitterMillis(kRtpJitterMillis);
-
-    EXPECT_EQ(threshold1, threshold2);
+    threshold2.setNotifyCurrentStatus(kNotifyCurrentStatus);
+    EXPECT_EQ(threshold, threshold2);
 }
 
 TEST_F(MediaQualityThresholdTest, TestNotEqual)
 {
-    threshold2.setRtpInactivityTimerMillis(5000);
+    MediaQualityThreshold threshold2;
+    threshold2.setRtpInactivityTimerMillis(std::vector<int32_t>{3000, 5000});
     threshold2.setRtcpInactivityTimerMillis(kRtcpInactivityTimerMillis);
+    threshold2.setRtpHysteresisTimeInMillis(kRtpHysteresisTimeInMillis);
     threshold2.setRtpPacketLossDurationMillis(kRtpPacketLossDurationMillis);
     threshold2.setRtpPacketLossRate(kRtpPacketLossRate);
-    threshold2.setJitterDurationMillis(kJitterDurationMillis);
     threshold2.setRtpJitterMillis(kRtpJitterMillis);
+    threshold2.setNotifyCurrentStatus(kNotifyCurrentStatus);
 
+    MediaQualityThreshold threshold3;
     threshold3.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis);
     threshold3.setRtcpInactivityTimerMillis(kRtcpInactivityTimerMillis);
+    threshold3.setRtpHysteresisTimeInMillis(kRtpHysteresisTimeInMillis);
     threshold3.setRtpPacketLossDurationMillis(kRtpPacketLossDurationMillis);
-    threshold3.setRtpPacketLossRate(1);
-    threshold3.setJitterDurationMillis(kJitterDurationMillis);
+    threshold3.setRtpPacketLossRate(std::vector<int32_t>{5, 10});
     threshold3.setRtpJitterMillis(kRtpJitterMillis);
+    threshold3.setNotifyCurrentStatus(kNotifyCurrentStatus);
 
-    EXPECT_NE(threshold1, threshold2);
-    EXPECT_NE(threshold1, threshold3);
+    EXPECT_NE(threshold, threshold2);
+    EXPECT_NE(threshold, threshold3);
 }
\ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtcpTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtcpTest.cpp
index 895f19c..1d165c6 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtcpTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtcpTest.cpp
@@ -74,7 +74,6 @@
     RtcpConfig rtcp;
     AmrParams amr;
     EvsParams evs;
-    MediaQualityThreshold threshold;
     int socketRtcpFd;
 
     virtual void SetUp() override
@@ -94,8 +93,6 @@
         evs.setUseHeaderFullOnly(kUseHeaderFullOnly);
         evs.setCodecModeRequest(kcodecModeRequest);
 
-        threshold.setRtcpInactivityTimerMillis(10000);
-
         config.setMediaDirection(kMediaDirection);
         config.setRemoteAddress(kRemoteAddress);
         config.setRemotePort(kRemotePort);
@@ -142,28 +139,9 @@
     EXPECT_EQ(graph->getState(), kStreamStateIdle);
 }
 
-TEST_F(AudioStreamGraphRtcpTest, TestGraphSetMediaThresholdFail)
-{
-    EXPECT_EQ(graph->setMediaQualityThreshold(&threshold), false);
-}
-
-TEST_F(AudioStreamGraphRtcpTest, TestGraphSetMediaThresholdSuccess)
-{
-    EXPECT_EQ(graph->create(&config), RESULT_SUCCESS);
-    EXPECT_EQ(graph->setMediaQualityThreshold(&threshold), true);
-    EXPECT_EQ(graph->start(), RESULT_SUCCESS);
-    EXPECT_EQ(graph->getState(), kStreamStateRunning);
-
-    // live update
-    EXPECT_EQ(graph->setMediaQualityThreshold(&threshold), true);
-    EXPECT_EQ(graph->stop(), RESULT_SUCCESS);
-    EXPECT_EQ(graph->getState(), kStreamStateCreated);
-}
-
 TEST_F(AudioStreamGraphRtcpTest, TestRtcpStreamAndUpdate)
 {
     EXPECT_EQ(graph->create(&config), RESULT_SUCCESS);
-    EXPECT_EQ(graph->setMediaQualityThreshold(&threshold), true);
     EXPECT_EQ(graph->start(), RESULT_SUCCESS);
     EXPECT_EQ(graph->getState(), kStreamStateRunning);
 
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRxTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRxTest.cpp
index 4f8cd55..f539e88 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRxTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRxTest.cpp
@@ -74,7 +74,6 @@
     RtcpConfig rtcp;
     AmrParams amr;
     EvsParams evs;
-    MediaQualityThreshold threshold;
     int socketRtpFd;
 
     virtual void SetUp() override
@@ -94,8 +93,6 @@
         evs.setUseHeaderFullOnly(kUseHeaderFullOnly);
         evs.setCodecModeRequest(kcodecModeRequest);
 
-        threshold.setRtpInactivityTimerMillis(10000);
-
         config.setMediaDirection(kMediaDirection);
         config.setRemoteAddress(kRemoteAddress);
         config.setRemotePort(kRemotePort);
@@ -142,28 +139,9 @@
     EXPECT_EQ(graph->getState(), kStreamStateIdle);
 }
 
-TEST_F(AudioStreamGraphRtpRxTest, TestGraphSetMediaThresholdFail)
-{
-    EXPECT_EQ(graph->setMediaQualityThreshold(&threshold), false);
-}
-
-TEST_F(AudioStreamGraphRtpRxTest, TestGraphSetMediaThresholdSuccess)
-{
-    EXPECT_EQ(graph->create(&config), RESULT_SUCCESS);
-    EXPECT_EQ(graph->setMediaQualityThreshold(&threshold), true);
-    EXPECT_EQ(graph->start(), RESULT_SUCCESS);
-    EXPECT_EQ(graph->getState(), kStreamStateRunning);
-
-    // live update
-    EXPECT_EQ(graph->setMediaQualityThreshold(&threshold), true);
-    EXPECT_EQ(graph->stop(), RESULT_SUCCESS);
-    EXPECT_EQ(graph->getState(), kStreamStateCreated);
-}
-
 TEST_F(AudioStreamGraphRtpRxTest, TestRtpRxStreamDirectionUpdate)
 {
     EXPECT_EQ(graph->create(&config), RESULT_SUCCESS);
-    EXPECT_EQ(graph->setMediaQualityThreshold(&threshold), true);
     EXPECT_EQ(graph->start(), RESULT_SUCCESS);
     EXPECT_EQ(graph->getState(), kStreamStateRunning);
 
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzerTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzerTest.cpp
index c0d7b2e..56bed86 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzerTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzerTest.cpp
@@ -62,26 +62,42 @@
 const int8_t kChannelAwareMode = 3;
 const bool kUseHeaderFullOnly = false;
 
+// MediaQualityThreshold
+const std::vector<int32_t> kRtpInactivityTimerMillis = {2000, 4000};
+const int32_t kRtcpInactivityTimerMillis = 2000;
+const int32_t kRtpHysteresisTimeInMillis = 2000;
+const int32_t kRtpPacketLossDurationMillis = 3000;
+const std::vector<int32_t> kRtpPacketLossRate = {3, 5};
+const std::vector<int32_t> kRtpJitterMillis = {10, 20};
+
 class FakeMediaQualityCallback : public BaseSessionCallback
 {
 public:
     FakeMediaQualityCallback() {}
     virtual ~FakeMediaQualityCallback() {}
 
-    virtual void SendEvent(int32_t type, uint64_t param1, uint64_t param2)
+    virtual void SendEvent(int32_t type, uint64_t param1, uint64_t /*param2*/)
     {
-        (void)param2;
-
         if (type == kAudioCallQualityChangedInd)
         {
-            MediaQuality* quality = reinterpret_cast<MediaQuality*>(param1);
+            CallQuality* quality = reinterpret_cast<CallQuality*>(param1);
 
             if (quality != nullptr)
             {
-                mMediaQuality = *quality;
+                mCallQuality = *quality;
                 delete quality;
             }
         }
+        else if (type == kImsMediaEventMediaQualityStatus)
+        {
+            MediaQualityStatus* status = reinterpret_cast<MediaQualityStatus*>(param1);
+
+            if (status != nullptr)
+            {
+                mStatus = *status;
+                delete status;
+            }
+        }
     }
 
     virtual void onEvent(int32_t type, uint64_t param1, uint64_t param2)
@@ -91,10 +107,12 @@
         (void)param2;
     }
 
-    MediaQuality getMediaQuality() { return mMediaQuality; }
+    CallQuality getCallQuality() { return mCallQuality; }
+    MediaQualityStatus getMediaQualityStatus() { return mStatus; }
 
 private:
-    MediaQuality mMediaQuality;
+    CallQuality mCallQuality;
+    MediaQualityStatus mStatus;
 };
 
 class MediaQualityAnalyzerTest : public ::testing::Test
@@ -171,10 +189,10 @@
     EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(1);
     mAnalyzer->start();
 
-    MediaQuality quality = mAnalyzer->getMediaQuality();
+    CallQuality quality = mAnalyzer->getCallQuality();
     mAnalyzer->stop();
 
-    EXPECT_EQ(mFakeCallback.getMediaQuality(), quality);
+    EXPECT_EQ(mFakeCallback.getCallQuality(), quality);
 }
 
 TEST_F(MediaQualityAnalyzerTest, TestCollectTxPackets)
@@ -194,30 +212,90 @@
     EXPECT_EQ(mAnalyzer->getTxPacketSize(), numPackets);
     EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);
     EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
-    MediaQuality quality = mAnalyzer->getMediaQuality();
+    CallQuality quality = mAnalyzer->getCallQuality();
     mAnalyzer->stop();
 
     EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
     EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);
     EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
 
-    // Check MediaQuality value
-    MediaQuality quality2 = mFakeCallback.getMediaQuality();
+    // Check CallQuality value
+    CallQuality quality2 = mFakeCallback.getCallQuality();
     EXPECT_EQ(quality2, quality);
     EXPECT_EQ(quality2.getNumRtpPacketsTransmitted(), numPackets);
 }
 
-TEST_F(MediaQualityAnalyzerTest, TestRxInactivityInd)
+TEST_F(MediaQualityAnalyzerTest, TestRtpInactivity)
+{
+    EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
+    EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(3);
+    MediaQualityThreshold threshold;
+    threshold.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis);
+    mAnalyzer->setMediaQualityThreshold(threshold);
+    mAnalyzer->start();
+    mCondition.wait_timeout(2100);  // 2.1 sec
+
+    // Check MediaQualityStatus value
+    MediaQualityStatus quality1 = mFakeCallback.getMediaQualityStatus();
+    EXPECT_EQ(quality1.getRtpInactivityTimeMillis(), 2000);
+
+    mCondition.wait_timeout(2100);  // 2.1 sec
+
+    // Check MediaQualityStatus value
+    MediaQualityStatus quality2 = mFakeCallback.getMediaQualityStatus();
+    EXPECT_EQ(quality2.getRtpInactivityTimeMillis(), 4000);
+
+    RtpPacket* packet = new RtpPacket();
+    packet->seqNum = 0;
+    mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
+
+    mCondition.wait_timeout(3100);  // 3.1 sec
+
+    MediaQualityStatus quality3 = mFakeCallback.getMediaQualityStatus();
+    EXPECT_EQ(quality3.getRtpInactivityTimeMillis(), 2000);
+    mAnalyzer->stop();
+}
+
+TEST_F(MediaQualityAnalyzerTest, TestRtcpInactivity)
+{
+    EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
+    EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(3);
+    MediaQualityThreshold threshold;
+    threshold.setRtcpInactivityTimerMillis(kRtcpInactivityTimerMillis);
+    mAnalyzer->setMediaQualityThreshold(threshold);
+    mAnalyzer->start();
+    mCondition.wait_timeout(2100);  // 2.1 sec
+
+    // Check MediaQualityStatus value
+    MediaQualityStatus quality1 = mFakeCallback.getMediaQualityStatus();
+    EXPECT_EQ(quality1.getRtcpInactivityTimeMillis(), 2000);
+
+    mCondition.wait_timeout(2100);  // 2.1 sec
+
+    // Check MediaQualityStatus value
+    MediaQualityStatus quality2 = mFakeCallback.getMediaQualityStatus();
+    EXPECT_EQ(quality2.getRtcpInactivityTimeMillis(), 2000);
+
+    mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtcp);
+
+    mCondition.wait_timeout(2100);  // 2.1 sec
+
+    MediaQualityStatus quality3 = mFakeCallback.getMediaQualityStatus();
+    EXPECT_EQ(quality3.getRtcpInactivityTimeMillis(), 2000);
+    mAnalyzer->stop();
+}
+
+TEST_F(MediaQualityAnalyzerTest, TestCallQualityInactivity)
 {
     EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
     mAnalyzer->start();
-    mCondition.wait_timeout(5100);  // 5.1 sec
+    mCondition.wait_timeout(4100);  // 4.1 sec
 
-    MediaQuality quality = mAnalyzer->getMediaQuality();
+    CallQuality quality = mAnalyzer->getCallQuality();
     mAnalyzer->stop();
 
-    // Check MediaQuality value
-    MediaQuality quality2 = mFakeCallback.getMediaQuality();
+    // Check CallQuality value
+    CallQuality quality2 = mFakeCallback.getCallQuality();
     EXPECT_EQ(quality2, quality);
     EXPECT_TRUE(quality2.getRtpInactivityDetected());
 }
@@ -256,26 +334,28 @@
     EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
     EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets - 1);
     EXPECT_EQ(mAnalyzer->getLostPacketSize(), 1);
-    MediaQuality quality = mAnalyzer->getMediaQuality();
+    CallQuality quality = mAnalyzer->getCallQuality();
     mAnalyzer->stop();
 
     EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
     EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);
     EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
 
-    // Check MediaQuality value
-    MediaQuality quality2 = mFakeCallback.getMediaQuality();
+    // Check CallQuality value
+    CallQuality quality2 = mFakeCallback.getCallQuality();
     EXPECT_EQ(quality2, quality);
     EXPECT_EQ(quality2.getNumRtpPacketsReceived(), numPackets - 1);
-    EXPECT_EQ(quality2.getDownlinkCallQualityLevel(), MediaQuality::kCallQualityBad);
+    EXPECT_EQ(quality2.getDownlinkCallQualityLevel(), CallQuality::kCallQualityBad);
 }
 
 TEST_F(MediaQualityAnalyzerTest, TestJitterInd)
 {
-    EXPECT_CALL(mCallback, onEvent(kImsMediaEventNotifyJitter, _, _)).Times(1);
+    EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(1);
     EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(1);
-    // set 10 milliseconds jitter threshold in 1 sec interval
-    mAnalyzer->setJitterThreshold(1, 10);
+    MediaQualityThreshold threshold;
+    threshold.setRtpHysteresisTimeInMillis(kRtpHysteresisTimeInMillis);
+    threshold.setRtpJitterMillis(kRtpJitterMillis);
+    mAnalyzer->setMediaQualityThreshold(threshold);
     mAnalyzer->start();
 
     const int32_t numPackets = 20;
@@ -297,17 +377,20 @@
     EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets);
     EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
 
-    MediaQuality quality = mAnalyzer->getMediaQuality();
+    CallQuality quality = mAnalyzer->getCallQuality();
     mAnalyzer->stop();
 
     EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
     EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);
     EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
 
-    MediaQuality quality2 = mFakeCallback.getMediaQuality();
+    CallQuality quality2 = mFakeCallback.getCallQuality();
     EXPECT_EQ(quality2, quality);
     EXPECT_EQ(quality2.getNumRtpPacketsReceived(), numPackets);
     EXPECT_EQ(quality2.getAverageRelativeJitter(), jitter);
+
+    MediaQualityStatus status = mFakeCallback.getMediaQualityStatus();
+    EXPECT_EQ(status.getRtpJitterMillis(), jitter);
 }
 
 TEST_F(MediaQualityAnalyzerTest, TestSsrcChange)
@@ -347,10 +430,13 @@
 
 TEST_F(MediaQualityAnalyzerTest, TestPacketLossInd)
 {
-    EXPECT_CALL(mCallback, onEvent(kImsMediaEventPacketLoss, _, _)).Times(1);
+    EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(1);
     EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(1);
-    // 1 percent packet loss threshold in 1 sec interval
-    mAnalyzer->setPacketLossThreshold(1, 1);
+    MediaQualityThreshold threshold;
+    threshold.setRtpHysteresisTimeInMillis(kRtpHysteresisTimeInMillis);
+    threshold.setRtpPacketLossDurationMillis(kRtpPacketLossDurationMillis);
+    threshold.setRtpPacketLossRate(kRtpPacketLossRate);
+    mAnalyzer->setMediaQualityThreshold(threshold);
     mAnalyzer->start();
 
     const int32_t numPackets = 10;
@@ -366,6 +452,7 @@
 
         packet->seqNum = i;
         packet->jitter = 10;
+        packet->arrival = ImsMediaTimer::GetTimeInMilliSeconds();
         mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
     }
 
@@ -378,14 +465,31 @@
     EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets - 1);
     EXPECT_EQ(mAnalyzer->getLostPacketSize(), 1);
 
-    MediaQuality quality = mAnalyzer->getMediaQuality();
+    CallQuality quality = mAnalyzer->getCallQuality();
     mAnalyzer->stop();
 
     EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
     EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);
     EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
 
-    MediaQuality quality2 = mFakeCallback.getMediaQuality();
+    CallQuality quality2 = mFakeCallback.getCallQuality();
     EXPECT_EQ(quality2, quality);
     EXPECT_EQ(quality2.getNumRtpPacketsNotReceived(), 1);
+
+    MediaQualityStatus status = mFakeCallback.getMediaQualityStatus();
+    EXPECT_EQ(status.getRtpPacketLossRate(), 10);
+}
+
+TEST_F(MediaQualityAnalyzerTest, TestNotifyMediaQualityStatus)
+{
+    EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(1);
+    EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(1);
+    MediaQualityThreshold threshold;
+    threshold.setNotifyCurrentStatus(true);
+    mAnalyzer->setMediaQualityThreshold(threshold);
+    mAnalyzer->start();
+
+    mCondition.wait_timeout(2100);  // 2.1 sec
+
+    mAnalyzer->stop();
 }
\ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpRxTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpRxTest.cpp
index 37641bc..202a158 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpRxTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpRxTest.cpp
@@ -45,6 +45,9 @@
 const int8_t kRedundantLevel = 3;
 const bool kKeepRedundantLevel = true;
 
+// inactivity timer
+const std::vector<int32_t> kRtpInactivityTimerMillis = {10000};
+
 class TextStreamGraphRtpRxTest : public ::testing::Test
 {
 public:
@@ -68,7 +71,7 @@
         rtcp.setTransmitPort(kTransmitPort);
         rtcp.setIntervalSec(kIntervalSec);
         rtcp.setRtcpXrBlockTypes(kRtcpXrBlockTypes);
-        threshold.setRtpInactivityTimerMillis(10000);
+        threshold.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis);
         config.setMediaDirection(kMediaDirection);
         config.setRemoteAddress(kRemoteAddress);
         config.setRemotePort(kRemotePort);
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpRxTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpRxTest.cpp
index e5e0b2e..800f0d2 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpRxTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpRxTest.cpp
@@ -58,6 +58,9 @@
 const int32_t kCvoValue = 1;
 const int32_t kRtcpFbTypes = VideoConfig::RTP_FB_NONE;
 
+// inactivity timer
+const std::vector<int32_t> kRtpInactivityTimerMillis = {10000};
+
 class VideoStreamGraphRtpRxTest : public ::testing::Test
 {
 public:
@@ -85,7 +88,7 @@
         rtcp.setTransmitPort(kTransmitPort);
         rtcp.setIntervalSec(kIntervalSec);
         rtcp.setRtcpXrBlockTypes(kRtcpXrBlockTypes);
-        threshold.setRtpInactivityTimerMillis(10000);
+        threshold.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis);
         config.setMediaDirection(kMediaDirection);
         config.setRemoteAddress(kRemoteAddress);
         config.setRemotePort(kRemotePort);