Merge Android 14 QPR2 to AOSP main

Bug: 319669529
Merged-In: I204e27a5a66b713002bd39ba57c7498147956a59
Change-Id: I46b4c2f5c7d57ebe588d8a000d46cd790ee1891d
diff --git a/OWNERS b/OWNERS
index 116f70a..0ba79c4 100644
--- a/OWNERS
+++ b/OWNERS
@@ -3,4 +3,5 @@
 amruthr@google.com
 seheele@google.com
 koshytc@google.com
-
+ericdavison@google.com
+radhikaagrawal@google.com
diff --git a/service/src/com/android/telephony/imsmedia/AudioSession.java b/service/src/com/android/telephony/imsmedia/AudioSession.java
index c3331d9..20a6781 100644
--- a/service/src/com/android/telephony/imsmedia/AudioSession.java
+++ b/service/src/com/android/telephony/imsmedia/AudioSession.java
@@ -469,6 +469,9 @@
 
     private void handleModifySessionRespose(AudioConfig config, int error) {
         try {
+            if (error != ImsMediaSession.RESULT_SUCCESS) {
+                Log.e(TAG, "modifySession failed with error: " + error);
+            }
             mCallback.onModifySessionResponse(config, error);
         }  catch (RemoteException e) {
             Log.e(TAG, "Failed to notify modifySessionResponse: " + e);
diff --git a/service/src/com/android/telephony/imsmedia/TextSession.java b/service/src/com/android/telephony/imsmedia/TextSession.java
index 37dd047..6c216c1 100644
--- a/service/src/com/android/telephony/imsmedia/TextSession.java
+++ b/service/src/com/android/telephony/imsmedia/TextSession.java
@@ -247,6 +247,9 @@
 
     private void handleModifySessionRespose(TextConfig config, int error) {
         try {
+            if (error != ImsMediaSession.RESULT_SUCCESS) {
+                Log.e(TAG, "modifySession failed with error: " + error);
+            }
             mCallback.onModifySessionResponse(config, error);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to notify modifySessionResponse: " + e);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/Android.bp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/Android.bp
index c92b7a1..903f469 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/Android.bp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/Android.bp
@@ -57,6 +57,9 @@
     cflags: [
         "-Wall",
     ],
+    shared_libs: [
+        "libmediautils",
+    ],
     sanitize: {
         cfi: true,
         scs: true,
@@ -91,5 +94,6 @@
         "libmediandk",
         "libnativewindow",
         "libutils",
+        "libmediautils",
     ],
 }
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/TextConfig.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/TextConfig.cpp
index 4181fc5..b1fb5ea 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/TextConfig.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/TextConfig.cpp
@@ -64,6 +64,7 @@
 {
     if (this != &config)
     {
+        RtpConfig::operator=(config);
         this->mCodecType = config.mCodecType;
         this->mBitrate = config.mBitrate;
         this->mRedundantPayload = config.mRedundantPayload;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/Android.bp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/Android.bp
index a6832c7..eee19e6 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/Android.bp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/Android.bp
@@ -119,7 +119,7 @@
     shared_libs: [
         "libnativewindow",
         "libcamera2ndk",
-        "libandroid"
+        "libandroid",
     ],
     include_dirs: [
         "frameworks/av/camera/ndk/include",
@@ -159,6 +159,9 @@
     local_include_dirs: [
         "include",
     ],
+    include_dirs: [
+        "frameworks/av/media/utils/include",
+    ],
     header_libs: [
         "libimsmedia_jni_headers",
         "libimsmedia_protocol_interface_headers",
@@ -177,5 +180,6 @@
         "liblog",
         "libmediandk",
         "libutils",
+        "libmediautils",
     ],
 }
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/JitterNetworkAnalyser.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/JitterNetworkAnalyser.cpp
index ee5f7a6..d19045b 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/JitterNetworkAnalyser.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/JitterNetworkAnalyser.cpp
@@ -21,13 +21,15 @@
 #include <numeric>
 #include <cmath>
 #include <algorithm>
+#include <climits>
 
 #define MAX_JITTER_LIST_SIZE    (150)
 #define PACKET_INTERVAL         (20)    // milliseconds
 #define BUFFER_INCREASE_TH      (200)   // milliseconds
-#define BUFFER_DECREASE_TH      (3000)  // milliseconds
-#define MARGIN_WEIGHT           (1.8f)
-#define BUFFER_IN_DECREASE_SIZE (1)
+#define BUFFER_DECREASE_TH      (2000)  // milliseconds
+#define MARGIN_WEIGHT           (1.0f)
+#define BUFFER_IN_DECREASE_SIZE (2)
+#define ROUNDUP_MARGIN          (10)  // milliseconds
 
 JitterNetworkAnalyser::JitterNetworkAnalyser()
 {
@@ -38,7 +40,7 @@
     mBufferStepSize = BUFFER_IN_DECREASE_SIZE;
     mBufferWeight = MARGIN_WEIGHT;
 
-    IMLOGD4("[JitterNetworkAnalyser] incThreshold[%d], decThreshold[%d], stepSize[%d], "
+    IMLOGD4("[JitterNetworkAnalyser] incThreshold=%d, decThreshold=%d, stepSize=%d, "
             "weight[%.3f]",
             mBufferIncThreshold, mBufferDecThreshold, mBufferStepSize, mBufferWeight);
     Reset();
@@ -54,9 +56,12 @@
 
     {
         std::lock_guard<std::mutex> guard(mMutex);
-        mListJitters.clear();
-        mMapDelta.clear();
+        mListAccumDeltas.clear();
+        mPrevTimestamp = 0;
+        mPrevArrivalTime = 0;
         mTimeLateArrivals = 0;
+        mPrevDelta = 0;
+        minJitterInBeginning = INT_MAX;
     }
 }
 
@@ -75,7 +80,7 @@
     mBufferStepSize = stepSize;
     mBufferWeight = weight;
 
-    IMLOGD4("[SetJitterOptions] incThreshold[%d], decThreshold[%d], stepSize[%d], weight[%.3f]",
+    IMLOGD4("[SetJitterOptions] incThreshold=%d, decThreshold=%d, stepSize=%d, weight[%.3f]",
             mBufferIncThreshold, mBufferDecThreshold, mBufferStepSize, mBufferWeight);
 }
 
@@ -95,40 +100,39 @@
 {
     std::lock_guard<std::mutex> guard(mMutex);
 
-    if (mMapDelta.size() == 0)
+    if (mPrevTimestamp == 0)
     {
-        mMapDelta.insert({timestamp, arrivalTime});
+        mPrevTimestamp = timestamp;
+        mPrevArrivalTime = arrivalTime;
+        minJitterInBeginning = INT_MAX;
         return 0;
     }
 
-    if (mMapDelta.size() > MAX_JITTER_LIST_SIZE)
+    int32_t inputTimestampGap = timestamp - mPrevTimestamp;
+    int32_t inputTimeGap = arrivalTime - mPrevArrivalTime;
+    int32_t delta = inputTimeGap - inputTimestampGap;
+
+    mPrevTimestamp = timestamp;
+    mPrevArrivalTime = arrivalTime;
+
+    mPrevDelta += delta;
+    mListAccumDeltas.push_back(
+            minJitterInBeginning == INT_MAX ? mPrevDelta : mPrevDelta - minJitterInBeginning);
+
+    if (mListAccumDeltas.size() > MAX_JITTER_LIST_SIZE)
     {
-        mMapDelta.erase(mMapDelta.begin());
+        mListAccumDeltas.pop_front();
+    }
+    else
+    {
+        // for normalization
+        if (minJitterInBeginning > mPrevDelta)
+        {
+            minJitterInBeginning = mPrevDelta;
+        }
     }
 
-    mMapDelta.insert({timestamp, arrivalTime});
-
-    if (getGreatestLess(mMapDelta, timestamp) == mMapDelta.end())
-    {
-        mListJitters.push_back(0);
-        return 0;
-    }
-
-    int32_t inputTimestampGap = timestamp - getGreatestLess(mMapDelta, timestamp)->first;
-    int32_t inputTimeGap = arrivalTime - getGreatestLess(mMapDelta, timestamp)->second;
-    int32_t jitter = std::abs(inputTimeGap - inputTimestampGap);
-
-    if (jitter < mMaxJitterBufferSize * PACKET_INTERVAL)
-    {
-        mListJitters.push_back(jitter);
-    }
-
-    if (mListJitters.size() > MAX_JITTER_LIST_SIZE)
-    {
-        mListJitters.pop_front();
-    }
-
-    return jitter;
+    return delta;
 }
 
 void JitterNetworkAnalyser::SetLateArrivals(uint32_t time)
@@ -140,23 +144,23 @@
 {
     std::lock_guard<std::mutex> guard(mMutex);
 
-    if (mListJitters.empty())
+    if (mListAccumDeltas.empty())
     {
         *pMean = 0;
         return 0.0f;
     }
 
-    double mean =
-            std::accumulate(mListJitters.begin(), mListJitters.end(), 0.0f) / mListJitters.size();
+    double mean = std::accumulate(mListAccumDeltas.begin(), mListAccumDeltas.end(), 0.0f) /
+            mListAccumDeltas.size();
 
     *pMean = mean;
 
-    double dev = sqrt(std::accumulate(mListJitters.begin(), mListJitters.end(), 0.0f,
+    double dev = sqrt(std::accumulate(mListAccumDeltas.begin(), mListAccumDeltas.end(), 0.0f,
                               [mean](int x, int y)
                               {
                                   return x + std::pow(y - mean, 2);
                               }) /
-            mListJitters.size());
+            mListAccumDeltas.size());
 
     return dev;
 }
@@ -165,12 +169,12 @@
 {
     std::lock_guard<std::mutex> guard(mMutex);
 
-    if (mListJitters.empty())
+    if (mListAccumDeltas.empty())
     {
         return 0;
     }
 
-    return *std::max_element(mListJitters.begin(), mListJitters.end());
+    return *std::max_element(mListAccumDeltas.begin(), mListAccumDeltas.end());
 }
 
 uint32_t JitterNetworkAnalyser::GetNextJitterBufferSize(
@@ -183,15 +187,14 @@
     double calcJitterSize = 0;
     int32_t maxJitter = GetMaxJitterValue();
     dev = CalculateDeviation(&mean);
-    calcJitterSize = (double)maxJitter * mBufferWeight;
+    calcJitterSize = (double)maxJitter * mBufferWeight + ROUNDUP_MARGIN;
+    uint32_t bufferSize = calcJitterSize / PACKET_INTERVAL;
 
-    if (calcJitterSize >= nCurrJitterBufferSize * PACKET_INTERVAL ||
-            maxJitter >= nCurrJitterBufferSize * PACKET_INTERVAL)
+    if (bufferSize > nCurrJitterBufferSize)
     {
         networkStatus = NETWORK_STATUS_BAD;
     }
-    else if (calcJitterSize < (nCurrJitterBufferSize - 1) * PACKET_INTERVAL &&
-            maxJitter < (nCurrJitterBufferSize - 1) * PACKET_INTERVAL - 10)
+    else if (bufferSize < nCurrJitterBufferSize - 1)
     {
         networkStatus = NETWORK_STATUS_GOOD;
     }
@@ -201,35 +204,28 @@
     }
 
     IMLOGD_PACKET6(IM_PACKET_LOG_JITTER,
-            "[GetNextJitterBufferSize] size[%4.2f], mean[%4.2f], dev[%4.2f], max[%d], curr[%d], "
-            "status[%d]",
+            "[GetNextJitterBufferSize] size=%4.2f, mean=%4.2f, dev=%4.2f, max=%d, curr=%d, "
+            "status=%d",
             calcJitterSize, mean, dev, maxJitter, nCurrJitterBufferSize, networkStatus);
 
     switch (networkStatus)
     {
         case NETWORK_STATUS_BAD:
         {
-            if (mBadStatusChangedTime == 0 ||
-                    (currentTime - mBadStatusChangedTime) >= mBufferIncThreshold)
+            nextJitterBuffer = bufferSize;
+
+            if (nextJitterBuffer > mMaxJitterBufferSize)
             {
-                nextJitterBuffer = (calcJitterSize + PACKET_INTERVAL) / PACKET_INTERVAL;
-
-                if (nextJitterBuffer > mMaxJitterBufferSize)
-                {
-                    nextJitterBuffer = mMaxJitterBufferSize;
-                }
-
-                if (nextJitterBuffer < mMinJitterBufferSize)
-                {
-                    nextJitterBuffer = mMinJitterBufferSize;
-                }
-
-                IMLOGD_PACKET2(IM_PACKET_LOG_JITTER,
-                        "[GetNextJitterBufferSize] increase curr[%d], next[%d]",
-                        nCurrJitterBufferSize, nextJitterBuffer);
-                mBadStatusChangedTime = currentTime;
+                nextJitterBuffer = mMaxJitterBufferSize;
+            }
+            else if (nextJitterBuffer < mMinJitterBufferSize)
+            {
+                nextJitterBuffer = mMinJitterBufferSize;
             }
 
+            IMLOGD_PACKET2(IM_PACKET_LOG_JITTER,
+                    "[GetNextJitterBufferSize] increase curr=%d, next=%d", nCurrJitterBufferSize,
+                    nextJitterBuffer);
             break;
         }
         case NETWORK_STATUS_GOOD:
@@ -246,13 +242,19 @@
                         (mTimeLateArrivals == 0 ||
                                 currentTime - mTimeLateArrivals > mBufferDecThreshold))
                 {
-                    if (nCurrJitterBufferSize > mMinJitterBufferSize)
+                    uint32_t decreaseStep = nCurrJitterBufferSize - bufferSize;
+
+                    decreaseStep > mBufferStepSize
+                            ? nextJitterBuffer = nCurrJitterBufferSize - mBufferStepSize
+                            : nextJitterBuffer = nCurrJitterBufferSize - decreaseStep;
+
+                    if (nextJitterBuffer < mMinJitterBufferSize)
                     {
-                        nextJitterBuffer = nCurrJitterBufferSize - mBufferStepSize;
+                        nextJitterBuffer = mMinJitterBufferSize;
                     }
 
                     IMLOGD_PACKET2(IM_PACKET_LOG_JITTER,
-                            "[GetNextJitterBufferSize] decrease curr[%d], next[%d]",
+                            "[GetNextJitterBufferSize] decrease curr=%d, next=%d",
                             nCurrJitterBufferSize, nextJitterBuffer);
                     networkStatus = NETWORK_STATUS_NORMAL;
                 }
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/StreamScheduler.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/StreamScheduler.cpp
index 9184212..f75efd2 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/StreamScheduler.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/StreamScheduler.cpp
@@ -72,7 +72,7 @@
     if (!mlistRegisteredNode.empty())
     {
         IMLOGD1("[Start] [%p] Start thread", this);
-        StartThread();
+        StartThread("StreamScheduler");
     }
 
     IMLOGD1("[Start] [%p] exit", this);
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 1a2cda5..74aad1e 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
@@ -134,7 +134,7 @@
 
 void AudioJitterBuffer::SetEvsRedundantFrameOffset(const int32_t offset)
 {
-    IMLOGD1("[SetEvsRedundantFrameOffset] offset[%d]", offset);
+    IMLOGD1("[SetEvsRedundantFrameOffset] offset=%d", offset);
     mEvsRedundantFrameOffset = offset;
 }
 
@@ -156,13 +156,13 @@
 
     if (subtype == MEDIASUBTYPE_REFRESHED)
     {
-        // nBufferSize is ssrc value
+        std::lock_guard<std::mutex> guard(mMutex);
         mSsrc = nBufferSize;
-        mTimeStarted = ImsMediaTimer::GetTimeInMilliSeconds();
+        mTimeStarted = arrivalTime;
         mJitterAnalyzer.Reset();
         mDataQueue.Add(&currEntry);
 
-        IMLOGI2("[Add] ssrc[%u], startTime[%d]", mSsrc, mTimeStarted);
+        IMLOGI2("[Add] ssrc=%u, startTime=%d", mSsrc, mTimeStarted);
         return;
     }
 
@@ -198,8 +198,8 @@
     std::lock_guard<std::mutex> guard(mMutex);
 
     IMLOGD_PACKET8(IM_PACKET_LOG_JITTER,
-            "[Add] seq[%d], mark[%d], TS[%d], size[%d], jitter[%d], queue[%d], playingDiff[%d], "
-            "arrival[%d]",
+            "[Add] seq=%d, mark=%d, TS=%d, size=%d, jitter=%d, queue=%d, playingDiff=%d, "
+            "arrival=%d",
             nSeqNum, bMark, nTimestamp, nBufferSize, jitter, mDataQueue.GetCount() + 1,
             mCurrPlayingTS - nTimestamp, arrivalTime);
 
@@ -249,6 +249,15 @@
             mListVoiceFrames.pop_front();
         }
     }
+
+    // update jitter buffer size
+    if (!mWaiting && mUpdatedDelay == 0)
+    {
+        uint32_t nextJitterBufferSize =
+                mJitterAnalyzer.GetNextJitterBufferSize(mCurrJitterBufferSize, arrivalTime);
+        mCheckUpdateJitterPacketCnt = 0;
+        mUpdatedDelay = nextJitterBufferSize - mCurrJitterBufferSize;
+    }
 }
 
 bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_t* pnDataSize,
@@ -257,15 +266,8 @@
 {
     std::lock_guard<std::mutex> guard(mMutex);
 
-    if (mPrevGetTime == 0)
-    {
-        mPrevGetTime = currentTime;
-    }
-    else
-    {
-        IMLOGD_PACKET1(IM_PACKET_LOG_JITTER, "[Get] time diff[%d]", currentTime - mPrevGetTime);
-        mPrevGetTime = currentTime;
-    }
+    IMLOGD_PACKET1(IM_PACKET_LOG_JITTER, "[Get] time diff=%d", currentTime - mPrevGetTime);
+    mPrevGetTime = currentTime;
 
     DataEntry* pEntry = nullptr;
     bool bForceToPlay = false;
@@ -283,34 +285,12 @@
         }
     }
 
-    // update jitter buffer size
-    if (!mWaiting && mUpdatedDelay == 0 &&
-            ((mDtxPlayed && mDataQueue.Get(&pEntry) &&
-                     pEntry->eDataType != MEDIASUBTYPE_AUDIO_SID) ||
-                    mCheckUpdateJitterPacketCnt * FRAME_INTERVAL > JITTER_BUFFER_UPDATE_INTERVAL))
-    {
-        uint32_t nextJitterBufferSize =
-                mJitterAnalyzer.GetNextJitterBufferSize(mCurrJitterBufferSize, currentTime);
-        mCheckUpdateJitterPacketCnt = 0;
-        mUpdatedDelay = nextJitterBufferSize - mCurrJitterBufferSize;
-
-        if (mDataQueue.GetCount() < mMinJitterBufferSize && mUpdatedDelay < 0)
-        {
-            IMLOGD_PACKET1(
-                    IM_PACKET_LOG_JITTER, "[Get] ignore decrease[%d]", mDataQueue.GetCount());
-            mUpdatedDelay = 0;
-        }
-        else
-        {
-            mCurrJitterBufferSize = nextJitterBufferSize;
-        }
-    }
-
     // increase delay
     if (!mWaiting && mDtxPlayed && mUpdatedDelay > 0)
     {
-        IMLOGD2("[Get] increase delay[%d], curTS[%d]", mUpdatedDelay, mCurrPlayingTS);
+        IMLOGD2("[Get] increase delay=%d, curTS=%d", mUpdatedDelay, mCurrPlayingTS);
         mUpdatedDelay--;
+        mCurrJitterBufferSize++;
         return false;
     }
 
@@ -318,9 +298,10 @@
     if (!mWaiting && mDataQueue.Get(&pEntry) && pEntry->eDataType == MEDIASUBTYPE_AUDIO_SID &&
             mUpdatedDelay < 0)
     {
-        IMLOGD3("[Get] decrease delay[%d], curTS[%u], queue[%u]", mUpdatedDelay, mCurrPlayingTS,
+        IMLOGD3("[Get] decrease delay=%d, curTS=%u, queue=%u", mUpdatedDelay, mCurrPlayingTS,
                 mDataQueue.GetCount());
         mUpdatedDelay++;
+        mCurrJitterBufferSize--;
         mCurrPlayingTS += FRAME_INTERVAL;
     }
 
@@ -332,13 +313,13 @@
     {
         if (mCurrJitterBufferSize == mMaxJitterBufferSize)
         {
-            IMLOGD1("[Get] resync, drop rate[%u]", dropRate);
+            IMLOGD1("[Get] resync, drop rate=%u", dropRate);
             mWaiting = true;
             mTimeStarted = currentTime;
         }
         else
         {
-            IMLOGD1("[Get] increase delay by drop rate[%u]", dropRate);
+            IMLOGD1("[Get] increase delay by drop rate=%u", dropRate);
             mCurrPlayingTS -= FRAME_INTERVAL;
             mCurrJitterBufferSize++;
         }
@@ -348,7 +329,7 @@
 
     if (mDataQueue.GetCount() == 0)
     {
-        IMLOGD_PACKET1(IM_PACKET_LOG_JITTER, "[Get] fail - empty, curTS[%u]", mCurrPlayingTS);
+        IMLOGD_PACKET1(IM_PACKET_LOG_JITTER, "[Get] fail - empty, curTS=%u", mCurrPlayingTS);
 
         if (!mWaiting)
         {
@@ -359,7 +340,7 @@
     }
     else if (mDataQueue.Get(&pEntry) && mWaiting)
     {
-        if (currentTime - mTimeStarted < mInitJitterBufferSize * FRAME_INTERVAL)
+        if (currentTime - mTimeStarted + ALLOWABLE_ERROR < mInitJitterBufferSize * FRAME_INTERVAL)
         {
             if (psubtype)
                 *psubtype = MEDIASUBTYPE_UNDEFINED;
@@ -376,10 +357,11 @@
             if (pDataType)
                 *pDataType = MEDIASUBTYPE_UNDEFINED;
 
-            IMLOGD_PACKET4(IM_PACKET_LOG_JITTER,
-                    "[Get] Wait - seq[%u], CurrJBSize[%u], delay[%u], QueueCount[%u]",
-                    pEntry->nSeqNum, mCurrJitterBufferSize, currentTime - pEntry->arrivalTime,
-                    GetCount());
+            IMLOGD_PACKET5(IM_PACKET_LOG_JITTER,
+                    "[Get] Wait - timeStarted=%d, seq=%u, CurrJBSize=%u, delay=%u, "
+                    "QueueCount=%u",
+                    mTimeStarted, pEntry->nSeqNum, mCurrJitterBufferSize,
+                    currentTime - pEntry->arrivalTime, GetCount());
             return false;
         }
         else
@@ -400,7 +382,7 @@
     // discard duplicated packet
     if (mDataQueue.Get(&pEntry) && mFirstFrameReceived && pEntry->nSeqNum == mLastPlayedSeqNum)
     {
-        IMLOGD6("[Get] duplicate - curTS[%u], seq[%d], mark[%d], TS[%u], size[%d], queue[%d]",
+        IMLOGD6("[Get] duplicate - curTS=%u, seq=%d, mark=%d, TS=%u, size=%d, queue=%d",
                 mCurrPlayingTS, pEntry->nSeqNum, pEntry->bMark, pEntry->nTimestamp,
                 pEntry->nBufferSize, mDataQueue.GetCount());
         CollectRxRtpStatus(pEntry->nSeqNum, kRtpStatusDuplicated);
@@ -419,11 +401,12 @@
 
     // adjust the playing timestamp
     if (mDataQueue.Get(&pEntry) && pEntry->nTimestamp != mCurrPlayingTS &&
-            ((mCurrPlayingTS - ALLOWABLE_ERROR) < pEntry->nTimestamp) &&
-            (pEntry->nTimestamp < (mCurrPlayingTS + ALLOWABLE_ERROR)))
+            ((mCurrPlayingTS - ALLOWABLE_ERROR) <= pEntry->nTimestamp) &&
+            (pEntry->nTimestamp <= (mCurrPlayingTS + ALLOWABLE_ERROR)))
     {
+        IMLOGD3("[Get] sync playing curTS=%u, TS=%u, seq=%d", mCurrPlayingTS, pEntry->nTimestamp,
+                pEntry->nSeqNum);
         mCurrPlayingTS = pEntry->nTimestamp;
-        IMLOGD2("[Get] sync playing curTS[%u], seq[%d]", mCurrPlayingTS, pEntry->nSeqNum);
     }
 
     // delete late arrival
@@ -439,9 +422,9 @@
             mLastPlayedSeqNum = pEntry->nSeqNum;
         }
 
-        IMLOGD_PACKET3(IM_PACKET_LOG_JITTER,
-                "[Get] delete late arrival seq[%d], curTS[%u], dtx[%d]", pEntry->nSeqNum,
-                mCurrPlayingTS, mDtxPlayed);
+        IMLOGD_PACKET4(IM_PACKET_LOG_JITTER,
+                "[Get] delete late arrival, dtx=%d, seq=%d, curTS=%u, TS=%u", mDtxPlayed,
+                pEntry->nSeqNum, mCurrPlayingTS, pEntry->nTimestamp);
 
         if (mPreservedDtx != nullptr)
         {
@@ -505,9 +488,9 @@
         }
 
         IMLOGD_PACKET7(IM_PACKET_LOG_JITTER,
-                "[Get] OK - dtx[%d], curTS[%u], seq[%u], TS[%u], size[%u], delay[%u], queue[%u]",
+                "[Get] OK, dtx=%d, curTS=%u, seq=%u, TS=%u, size=%u, delay=%u, curSize=%u",
                 mDtxPlayed, mCurrPlayingTS, pEntry->nSeqNum, pEntry->nTimestamp,
-                pEntry->nBufferSize, currentTime - pEntry->arrivalTime, mDataQueue.GetCount());
+                pEntry->nBufferSize, currentTime - pEntry->arrivalTime, mCurrJitterBufferSize);
 
         mCurrPlayingTS = pEntry->nTimestamp + FRAME_INTERVAL;
         mFirstFrameReceived = true;
@@ -552,7 +535,7 @@
                 *pDataType = pEntry->eDataType;
 
             IMLOGD_PACKET3(IM_PACKET_LOG_JITTER,
-                    "[Get] preserved frame, dtx[%d], curTS[%u], current[%u]", mDtxPlayed,
+                    "[Get] OK, preserved frame, dtx=%d, curTS=%u, current=%u", mDtxPlayed,
                     mCurrPlayingTS, currentTime);
 
             mLastPlayedSeqNum = pEntry->nSeqNum;
@@ -574,7 +557,7 @@
         if (pDataType)
             *pDataType = MEDIASUBTYPE_UNDEFINED;
 
-        IMLOGD_PACKET3(IM_PACKET_LOG_JITTER, "[Get] fail - dtx[%d], curTS[%u], current[%u]",
+        IMLOGD_PACKET3(IM_PACKET_LOG_JITTER, "[Get] fail - dtx=%d, curTS=%u, current=%u",
                 mDtxPlayed, mCurrPlayingTS, currentTime);
 
         mCurrPlayingTS += FRAME_INTERVAL;
@@ -597,9 +580,9 @@
 
     while (mDataQueue.Get(&entry) && GetCount() > spareFrames)
     {
-        IMLOGD6("[Resync] state[%d], seq[%d], TS[%d], dtx[%d], queue[%d], spareFrames[%d]",
-                mWaiting, entry->nSeqNum, entry->nTimestamp,
-                entry->eDataType == MEDIASUBTYPE_AUDIO_SID, GetCount(), spareFrames);
+        IMLOGD6("[Resync] state=%d, seq=%d, TS=%d, dtx=%d, queue=%d, spareFrames=%d", mWaiting,
+                entry->nSeqNum, entry->nTimestamp, entry->eDataType == MEDIASUBTYPE_AUDIO_SID,
+                GetCount(), spareFrames);
 
         if (entry->eDataType != MEDIASUBTYPE_AUDIO_SID)
         {
@@ -629,7 +612,7 @@
     if (lostGap > 1 && lostGap < SEQ_OUTLIER_THRESHOLD)
     {
         uint16_t lostSeq = lastSeq + 1;
-        IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[CountLostFrames] lost seq[%u], num[%u]", lostSeq,
+        IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[CountLostFrames] lost seq=%u, num=%u", lostSeq,
                 lostGap - 1);
 
         SessionCallbackParameter* param =
@@ -663,8 +646,6 @@
 
 void AudioJitterBuffer::CollectRxRtpStatus(int32_t seq, kRtpPacketStatus status)
 {
-    IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[CollectRxRtpStatus] seq[%d], status[%d]", seq, status);
-
     if (mCallback != nullptr)
     {
         SessionCallbackParameter* param =
@@ -675,9 +656,6 @@
 
 void AudioJitterBuffer::CollectJitterBufferStatus(int32_t currSize, int32_t maxSize)
 {
-    IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[CollectJitterBufferStatus] currSize[%d], maxSize[%d]",
-            currSize, maxSize);
-
     if (mCallback != nullptr)
     {
         mCallback->SendEvent(kCollectJitterBufferSize, currSize, maxSize);
@@ -710,7 +688,7 @@
     {
         *entry = nullptr;
         IMLOGD_PACKET1(IM_PACKET_LOG_JITTER,
-                "[GetPartialRedundancyFrame] lostSeq[%d] Redundant Frame not found", lostSeq);
+                "[GetPartialRedundancyFrame] lostSeq=%d Redundant Frame not found", lostSeq);
         return false;
     }
 
@@ -718,7 +696,7 @@
     {
         *entry = nullptr;
         IMLOGD_PACKET1(IM_PACKET_LOG_JITTER,
-                "[GetPartialRedundancyFrame] lostSeq[%d] Redundant Frame is SID", lostSeq);
+                "[GetPartialRedundancyFrame] lostSeq=%d Redundant Frame is SID", lostSeq);
         return false;
     }
 
@@ -729,7 +707,7 @@
         *entry = nullptr;
         IMLOGD_PACKET2(IM_PACKET_LOG_JITTER,
                 "[GetPartialRedundancyFrame] RF not in offset timeframe. \
-                RF_timestamp[%u] LostFrame_timestamp[%u]",
+                RF_timestamp=%u LostFrame_timestamp=%u",
                 tempEntry->nTimestamp, currentTimestamp);
         return false;
     }
@@ -738,14 +716,14 @@
     {
         *entry = tempEntry;
         IMLOGD_PACKET4(IM_PACKET_LOG_JITTER,
-                "[GetPartialRedundancyFrame] lostSeq[%d] RFSeq[%d], size[%d] , curTS[%u]", lostSeq,
+                "[GetPartialRedundancyFrame] lostSeq=%d RFSeq=%d, size=%d , curTS=%u", lostSeq,
                 tempEntry->nSeqNum, tempEntry->nBufferSize, mCurrPlayingTS);
         return true;
     }
 
     *entry = nullptr;
     IMLOGD_PACKET1(IM_PACKET_LOG_JITTER,
-            "[GetPartialRedundancyFrame] lostSeq[%d] Redundant Frame not found", lostSeq);
+            "[GetPartialRedundancyFrame] lostSeq=%d Redundant Frame not found", lostSeq);
     return false;
 }
 
@@ -761,7 +739,7 @@
                                 ? 1
                                 : 0];
         IMLOGD_PACKET2(IM_PACKET_LOG_JITTER,
-                "[GetNextFrameFirstByte] nextSeq[%d] nextFrameFirstByte[%02X]", pEntry->nSeqNum,
+                "[GetNextFrameFirstByte] nextSeq=%d nextFrameFirstByte[%02X]", pEntry->nSeqNum,
                 nextFrameFirstByte[0]);
         return true;
     }
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 b7ce3db..b3b51bd 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
@@ -108,22 +108,22 @@
     {
         if ((config->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE ||
                     config->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY ||
-                    config->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_ONLY) &&
-                isOtherSessionActive(sessionId))
+                    config->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_ONLY))
         {
-            return RESULT_NO_RESOURCES;
+            if (!deactivateOtherSessionIfActive(sessionId))
+            {
+                return RESULT_NO_RESOURCES;
+            }
+        }
+
+        if ((session->second)->IsGraphAlreadyExist(config) ||
+                (session->second)->getGraphSize(kStreamRtpTx) == 0)
+        {
+            return (session->second)->startGraph(config);
         }
         else
         {
-            if ((session->second)->IsGraphAlreadyExist(config) ||
-                    (session->second)->getGraphSize(kStreamRtpTx) == 0)
-            {
-                return (session->second)->startGraph(config);
-            }
-            else
-            {
-                return (session->second)->addGraph(config, false);
-            }
+            return (session->second)->addGraph(config, false);
         }
     }
     else
@@ -566,7 +566,7 @@
     }
 }
 
-bool AudioManager::isOtherSessionActive(const int sessionId)
+bool AudioManager::deactivateOtherSessionIfActive(const int sessionId)
 {
     for (auto const& session : mSessions)
     {
@@ -577,9 +577,15 @@
                     state == kSessionStateSending)
             {
                 IMLOGE1("[modifySession] Another session id[%d] is active", session.first);
-                return true;
+                if ((session.second)->deactivate())
+                {
+                    IMLOGI1("[modifySession] Moved session id[%d] to inactive", session.first);
+                    return true;
+                }
+                IMLOGE1("[modifySession] Failed to move session id[%d] to inactive", session.first);
+                return false;
             }
         }
     }
-    return false;
-}
+    return true;
+}
\ No newline at end of file
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 dd763e3..c06ddc3 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
@@ -657,4 +657,34 @@
         default:
             break;
     }
+}
+
+bool AudioSession::deactivate()
+{
+    IMLOGI0("[deactivate]");
+
+    for (auto& graph : mListGraphRtpTx)
+    {
+        if (graph != nullptr)
+        {
+            graph->stop();
+        }
+    }
+
+    for (auto& graph : mListGraphRtpRx)
+    {
+        if (graph != nullptr)
+        {
+            graph->stop();
+        }
+    }
+
+    SessionState state = getState();
+    if (state == kSessionStateActive || state == kSessionStateReceiving ||
+            state == kSessionStateSending)
+    {
+        return false;
+    }
+
+    return true;
 }
\ No newline at end of file
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 7266551..0f19b63 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
@@ -109,24 +109,15 @@
     }
 
     ImsMediaResult ret = RESULT_NOT_READY;
+    bool needsToStart = false;
 
     if (mGraphState == kStreamStateRunning)
     {
-        mScheduler->Stop();
-
-        for (auto& node : mListNodeStarted)
-        {
-            IMLOGD1("[update] update node[%s]", node->GetNodeName());
-            ret = node->UpdateConfig(mConfig);
-
-            if (ret != RESULT_SUCCESS)
-            {
-                IMLOGE2("[update] error in update node[%s], ret[%d]", node->GetNodeName(), ret);
-            }
-        }
-        mScheduler->Start();
+        stop();
+        needsToStart = true;
     }
-    else if (mGraphState == kStreamStateCreated)
+
+    if (mGraphState == kStreamStateCreated)
     {
         for (auto& node : mListNodeToStart)
         {
@@ -148,6 +139,11 @@
         return start();
     }
 
+    if (needsToStart)
+    {
+        return start();
+    }
+
     return ret;
 }
 
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp
index a125eae..8c84509 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp
@@ -20,6 +20,7 @@
 #include <AudioConfig.h>
 #include <IAudioSourceNode.h>
 #include <DtmfEncoderNode.h>
+#include <DtmfSenderNode.h>
 #include <AudioRtpPayloadEncoderNode.h>
 #include <RtpEncoderNode.h>
 #include <SocketWriterNode.h>
@@ -196,9 +197,16 @@
     AddNode(pDtmfEncoderNode);
     mListDtmfNodes.push_back(pDtmfEncoderNode);
 
+    BaseNode* pDtmfSenderNode = new DtmfSenderNode(mCallback);
+    pDtmfSenderNode->SetMediaType(IMS_MEDIA_AUDIO);
+    pDtmfSenderNode->SetConfig(audioConfig);
+    pDtmfEncoderNode->ConnectRearNode(pDtmfSenderNode);
+    AddNode(pDtmfSenderNode);
+    mListDtmfNodes.push_back(pDtmfSenderNode);
+
     if (rtpEncoderNode != nullptr)
     {
-        pDtmfEncoderNode->ConnectRearNode(rtpEncoderNode);
+        pDtmfSenderNode->ConnectRearNode(rtpEncoderNode);
     }
 
     return true;
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 a011217..b361eb6 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
@@ -150,7 +150,7 @@
     {
         IMLOGD0("[start]");
         mTimeStarted = ImsMediaTimer::GetTimeInMilliSeconds();
-        StartThread();
+        StartThread("MediaQualityAnalyzer");
     }
 }
 
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/ImsMediaAudioSource.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/ImsMediaAudioSource.cpp
index 705bceb..b0467dd 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/ImsMediaAudioSource.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/ImsMediaAudioSource.cpp
@@ -167,7 +167,7 @@
     IMLOGI1("[Start] start stream state[%s]", AAudio_convertStreamStateToText(nextState));
 
     // start audio read thread
-    StartThread();
+    StartThread("ImsMediaAudioSource");
     return true;
 }
 
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadDecoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadDecoderNode.cpp
index c284b25..d465694 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadDecoderNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadDecoderNode.cpp
@@ -125,7 +125,8 @@
 {
     if (subtype == MEDIASUBTYPE_REFRESHED)
     {
-        SendDataToRearNode(subtype, nullptr, nDataSize, 0, 0, 0, MEDIASUBTYPE_UNDEFINED);
+        SendDataToRearNode(
+                subtype, nullptr, nDataSize, 0, 0, 0, MEDIASUBTYPE_UNDEFINED, arrivalTime);
         return;
     }
 
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadEncoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadEncoderNode.cpp
index e342951..4bc2c43 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadEncoderNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadEncoderNode.cpp
@@ -96,7 +96,7 @@
     {
         case kAudioCodecAmr:
         case kAudioCodecAmrWb:
-            EncodePayloadAmr(pData, nDataSize, nTimestamp);
+            EncodePayloadAmr(pData, nDataSize, nTimestamp, arrivalTime);
             break;
         case kAudioCodecPcmu:
         case kAudioCodecPcma:
@@ -104,7 +104,7 @@
                     nSeqNum, nDataType, arrivalTime);
             break;
         case kAudioCodecEvs:
-            EncodePayloadEvs(pData, nDataSize, nTimestamp);
+            EncodePayloadEvs(pData, nDataSize, nTimestamp, arrivalTime);
             break;
         default:
             IMLOGE1("[OnDataFromFrontNode] invalid codec type[%d]", mCodecType);
@@ -167,7 +167,7 @@
 }
 
 void AudioRtpPayloadEncoderNode::EncodePayloadAmr(
-        uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp)
+        uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp, uint32_t arrivalTime)
 {
     uint32_t nCmr = 15;
     uint32_t f, ft, q, nDataBitSize;
@@ -260,8 +260,8 @@
 
         if (mTotalPayloadSize > 0)
         {
-            SendDataToRearNode(
-                    MEDIASUBTYPE_RTPPAYLOAD, mPayload, nTotalSize, mTimestamp, mFirstFrame, 0);
+            SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, mPayload, nTotalSize, mTimestamp,
+                    mFirstFrame, 0, MEDIASUBTYPE_UNDEFINED, arrivalTime);
         }
 
         mCurrNumOfFrame = 0;
@@ -275,7 +275,7 @@
 }
 
 void AudioRtpPayloadEncoderNode::EncodePayloadEvs(
-        uint8_t* pData, uint32_t nDataSize, uint32_t nTimeStamp)
+        uint8_t* pData, uint32_t nDataSize, uint32_t nTimeStamp, uint32_t arrivalTime)
 {
     if (nDataSize == 0)
     {
@@ -334,8 +334,8 @@
 
             if (mTotalPayloadSize > 0)
             {
-                SendDataToRearNode(
-                        MEDIASUBTYPE_RTPPAYLOAD, mPayload, nTotalSize, mTimestamp, mFirstFrame, 0);
+                SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, mPayload, nTotalSize, mTimestamp,
+                        mFirstFrame, 0, MEDIASUBTYPE_UNDEFINED, arrivalTime);
             }
 
             mCurrNumOfFrame = 0;
@@ -421,8 +421,8 @@
 
             if (mTotalPayloadSize > 0)
             {
-                SendDataToRearNode(
-                        MEDIASUBTYPE_RTPPAYLOAD, mPayload, nTotalSize, mTimestamp, mFirstFrame, 0);
+                SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, mPayload, nTotalSize, mTimestamp,
+                        mFirstFrame, 0, MEDIASUBTYPE_UNDEFINED, arrivalTime);
             }
 
             mCurrNumOfFrame = 0;
@@ -519,7 +519,8 @@
                 if (mTotalPayloadSize > 0)
                 {
                     SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, mPayload,
-                            CheckPaddingNecessity(nTotalSize), mTimestamp, mFirstFrame, 0);
+                            CheckPaddingNecessity(nTotalSize), mTimestamp, mFirstFrame, 0,
+                            MEDIASUBTYPE_UNDEFINED, arrivalTime);
                 }
 
                 mCurrNumOfFrame = 0;
@@ -600,7 +601,8 @@
                 if (mTotalPayloadSize > 0)
                 {
                     SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, mPayload,
-                            CheckPaddingNecessity(nTotalSize), mTimestamp, mFirstFrame, 0);
+                            CheckPaddingNecessity(nTotalSize), mTimestamp, mFirstFrame, 0,
+                            MEDIASUBTYPE_UNDEFINED, arrivalTime);
                 }
 
                 mCurrNumOfFrame = 0;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/DtmfEncoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/DtmfEncoderNode.cpp
index a3b750e..cb93606 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/DtmfEncoderNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/DtmfEncoderNode.cpp
@@ -51,7 +51,7 @@
 {
     mAudioFrameDuration = mSamplingRate * mPtime;
     IMLOGD1("[Start] interval[%d]", mAudioFrameDuration);
-    StartThread();
+    StartThread("DtmfEncoderNode");
     mNodeState = kNodeStateRunning;
     return RESULT_SUCCESS;
 }
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/DtmfSenderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/DtmfSenderNode.cpp
new file mode 100644
index 0000000..d7d1120
--- /dev/null
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/DtmfSenderNode.cpp
@@ -0,0 +1,128 @@
+/**
+ * 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 <ImsMediaDefine.h>
+#include <ImsMediaTrace.h>
+#include <DtmfSenderNode.h>
+#include <ImsMediaTimer.h>
+#include <AudioConfig.h>
+
+DtmfSenderNode::DtmfSenderNode(BaseSessionCallback* callback) :
+        BaseNode(callback)
+{
+    mNextTime = 0;
+    mPrevTime = 0;
+    mPtime = 20;
+}
+
+DtmfSenderNode::~DtmfSenderNode() {}
+
+kBaseNodeId DtmfSenderNode::GetNodeId()
+{
+    return kNodeIdDtmfSender;
+}
+
+ImsMediaResult DtmfSenderNode::Start()
+{
+    mNextTime = 0;
+    mNodeState = kNodeStateRunning;
+    return RESULT_SUCCESS;
+}
+
+void DtmfSenderNode::Stop()
+{
+    mNextTime = 0;
+    ClearDataQueue();
+    mNodeState = kNodeStateStopped;
+}
+
+bool DtmfSenderNode::IsRunTime()
+{
+    return false;
+}
+
+bool DtmfSenderNode::IsSourceNode()
+{
+    return false;
+}
+
+void DtmfSenderNode::SetConfig(void* config)
+{
+    AudioConfig* pConfig = reinterpret_cast<AudioConfig*>(config);
+
+    if (pConfig != nullptr)
+    {
+        mPtime = pConfig->getPtimeMillis();
+    }
+}
+
+bool DtmfSenderNode::IsSameConfig(void* config)
+{
+    if (config == nullptr)
+    {
+        return true;
+    }
+
+    AudioConfig* pConfig = reinterpret_cast<AudioConfig*>(config);
+    return (mPtime == pConfig->getPtimeMillis());
+}
+
+void DtmfSenderNode::ProcessData()
+{
+    ImsMediaSubType subtype;
+    uint8_t* data;
+    uint32_t size;
+    uint32_t timestamp;
+    bool bMark;
+    uint32_t currTime;
+
+    if (GetData(&subtype, &data, &size, &timestamp, &bMark, nullptr) == false)
+    {
+        return;
+    }
+
+    currTime = ImsMediaTimer::GetTimeInMilliSeconds();
+
+    if (mNextTime && !(currTime >= mNextTime || currTime < mPrevTime || mNextTime < mPrevTime))
+    {
+        mPrevTime = currTime;
+        return;
+    }
+
+    if (subtype == MEDIASUBTYPE_DTMFSTART)
+    {
+        SendDataToRearNode(subtype, data, size, currTime, bMark, 0);
+        DeleteData();
+        mNextTime = currTime;
+
+        // send the first dtmf packet
+        if (GetData(&subtype, &data, &size, &timestamp, &bMark, nullptr, nullptr) &&
+                subtype == MEDIASUBTYPE_DTMF_PAYLOAD)
+        {
+            SendDataToRearNode(subtype, data, size, currTime, bMark, 0);
+            DeleteData();
+            mNextTime += mPtime;
+        }
+    }
+    else
+    {
+        SendDataToRearNode(subtype, data, size, currTime, bMark, 0);
+        DeleteData();
+        mNextTime += mPtime;
+    }
+
+    mPrevTime = currTime;
+}
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioPlayerNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioPlayerNode.cpp
index fbc04a9..5fdc9d9 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioPlayerNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioPlayerNode.cpp
@@ -27,7 +27,7 @@
 #define MAX_CODEC_EVS_AMR_IO_MODE 9
 #define JITTER_BUFFER_SIZE_INIT   3
 #define JITTER_BUFFER_SIZE_MIN    3
-#define JITTER_BUFFER_SIZE_MAX    13
+#define JITTER_BUFFER_SIZE_MAX    11
 
 IAudioPlayerNode::IAudioPlayerNode(BaseSessionCallback* callback) :
         JitterBufferControlNode(callback, IMS_MEDIA_AUDIO)
@@ -95,7 +95,7 @@
     }
 
     mNodeState = kNodeStateRunning;
-    StartThread();
+    StartThread("IAudioPlayerNode");
     return RESULT_SUCCESS;
 }
 
@@ -297,7 +297,7 @@
 void* IAudioPlayerNode::run()
 {
     IMLOGD0("[run] enter");
-    SetAudioThreadPriority(gettid());
+    SetThreadPriority(getpid(), gettid(), THREAD_PRIORITY_REALTIME);
     ImsMediaSubType subtype = MEDIASUBTYPE_UNDEFINED;
     ImsMediaSubType datatype = MEDIASUBTYPE_UNDEFINED;
     uint8_t* data = nullptr;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioSourceNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioSourceNode.cpp
index 89a14b8..51de7fd 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioSourceNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioSourceNode.cpp
@@ -18,6 +18,7 @@
 #include <ImsMediaAudioSource.h>
 #include <ImsMediaTrace.h>
 #include <ImsMediaAudioUtil.h>
+#include <ImsMediaTimer.h>
 #include <string.h>
 #include <AudioConfig.h>
 #include <RtpConfig.h>
@@ -181,8 +182,8 @@
 {
     IMLOGD_PACKET3(IM_PACKET_LOG_AUDIO, "[onDataFrame] size[%zu], TS[%ld], flag[%d]", size,
             timestamp, flag);
-    SendDataToRearNode(
-            MEDIASUBTYPE_UNDEFINED, buffer, size, timestamp, !mFirstFrame, MEDIASUBTYPE_UNDEFINED);
+    SendDataToRearNode(MEDIASUBTYPE_UNDEFINED, buffer, size, ImsMediaTimer::GetTimeInMilliSeconds(),
+            !mFirstFrame, 0, MEDIASUBTYPE_UNDEFINED, ImsMediaTimer::GetTimeInMilliSeconds());
 
     if (!mFirstFrame)
     {
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/JitterNetworkAnalyser.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/JitterNetworkAnalyser.h
index 77a8910..1de0e7e 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/JitterNetworkAnalyser.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/JitterNetworkAnalyser.h
@@ -73,8 +73,11 @@
     std::mutex mMutex;
     uint32_t mMinJitterBufferSize;
     uint32_t mMaxJitterBufferSize;
-    std::map<int32_t, int32_t> mMapDelta;
-    std::list<int32_t> mListJitters;
+    uint32_t mPrevTimestamp;
+    uint32_t mPrevArrivalTime;
+    std::list<int32_t> mListAccumDeltas;
+    int32_t mPrevDelta;
+    int32_t minJitterInBeginning;
     uint32_t mTimeLateArrivals;
     NETWORK_STATUS mNetworkStatus;
     uint32_t mGoodStatusEnteringTime;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h
index d0f9fce..17a1ebd 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h
@@ -71,7 +71,7 @@
     virtual void setMediaQualityThreshold(int sessionId, MediaQualityThreshold* threshold);
     virtual void SendInternalEvent(
             uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
-    virtual bool isOtherSessionActive(const int sessionId);
+    virtual bool deactivateOtherSessionIfActive(const int sessionId);
 
     static AudioManager* sManager;
     std::unordered_map<int, std::unique_ptr<AudioSession>> mSessions;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioSession.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioSession.h
index ac29bfd..40e8313 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioSession.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioSession.h
@@ -111,6 +111,13 @@
      */
     void sendRtpHeaderExtension(std::list<RtpHeaderExtension>* listExtension);
 
+    /**
+     * @brief Move session to inactive. i.e., Rtp Tx and Rtp Rx graphs are stopped
+     *
+     * @return bool false if failed to move session to inactive
+     */
+    bool deactivate();
+
 private:
     std::list<AudioStreamGraphRtpTx*> mListGraphRtpTx;
     std::list<AudioStreamGraphRtpRx*> mListGraphRtpRx;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpTx.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpTx.h
index 36d1b6e..1b7d2c1 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpTx.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtpTx.h
@@ -35,7 +35,7 @@
      *
      * @param config AudioConfig for setting the parameters for nodes
      * @param rtpEncoderNode The RtpEncoderNode instance to connect as a rear node after the
-     * DtmfEncoderNode, if it is null, no dtmf packet will be delivered to RtpEncoderNode.
+     * DtmfSenderNode, if it is null, no dtmf packet will be delivered to RtpEncoderNode.
      * @return true Returns when the graph created without error
      * @return false Returns when the given parameters are invalid.
      */
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/AudioRtpPayloadEncoderNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/AudioRtpPayloadEncoderNode.h
index cc3be7f..482e5da 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/AudioRtpPayloadEncoderNode.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/AudioRtpPayloadEncoderNode.h
@@ -38,8 +38,10 @@
     virtual bool IsSameConfig(void* config);
 
 private:
-    void EncodePayloadAmr(uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp);
-    void EncodePayloadEvs(uint8_t* pData, uint32_t nDataSize, uint32_t nTimeStamp);
+    void EncodePayloadAmr(
+            uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp, uint32_t arrivalTime);
+    void EncodePayloadEvs(
+            uint8_t* pData, uint32_t nDataSize, uint32_t nTimeStamp, uint32_t arrivalTime);
     uint32_t CheckPaddingNecessity(uint32_t nTotalSize);
 
     int32_t mCodecType;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/DtmfSenderNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/DtmfSenderNode.h
new file mode 100644
index 0000000..7057676
--- /dev/null
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/DtmfSenderNode.h
@@ -0,0 +1,43 @@
+/**
+ * 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 DTMFSENDERNODE_H_INCLUDED
+#define DTMFSENDERNODE_H_INCLUDED
+
+#include <ImsMediaDefine.h>
+#include <BaseNode.h>
+
+class DtmfSenderNode : public BaseNode
+{
+public:
+    DtmfSenderNode(BaseSessionCallback* callback = nullptr);
+    virtual ~DtmfSenderNode();
+    virtual kBaseNodeId GetNodeId();
+    virtual ImsMediaResult Start();
+    virtual void Stop();
+    virtual bool IsRunTime();
+    virtual bool IsSourceNode();
+    virtual void SetConfig(void* config);
+    virtual bool IsSameConfig(void* config);
+    virtual void ProcessData();
+
+private:
+    uint32_t mNextTime;
+    uint32_t mPrevTime;
+    int8_t mPtime;  // msec unit, interval between dtmf packets
+};
+
+#endif  // DTMFSENDERNODE_H_INCLUDED
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/BaseNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/BaseNode.h
index 8f99c98..f9e0d5b 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/BaseNode.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/BaseNode.h
@@ -49,6 +49,7 @@
     kNodeIdAudioSource,
     kNodeIdAudioPlayer,
     kNodeIdDtmfEncoder,
+    kNodeIdDtmfSender,
     kNodeIdAudioPayloadEncoder,
     kNodeIdAudioPayloadDecoder,
     // for Video
@@ -142,7 +143,7 @@
     /**
      * @brief Checks the node processes data in main thread.
      */
-    virtual bool IsRunTime() = 0;
+    virtual bool IsRunTime();
 
     /**
      * @brief Checks the node to start in main thread
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpEncoderNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpEncoderNode.h
index d1446f2..f53829a 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpEncoderNode.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpEncoderNode.h
@@ -31,13 +31,15 @@
     virtual kBaseNodeId GetNodeId();
     virtual ImsMediaResult Start();
     virtual void Stop();
-    virtual void ProcessData();
-    virtual bool IsRunTime();
+    virtual void OnDataFromFrontNode(ImsMediaSubType subtype, uint8_t* data, uint32_t size,
+            uint32_t timestamp, bool mark, uint32_t seq,
+            ImsMediaSubType dataType = ImsMediaSubType::MEDIASUBTYPE_UNDEFINED,
+            uint32_t arrivalTime = 0);
     virtual bool IsSourceNode();
     virtual void SetConfig(void* config);
     virtual bool IsSameConfig(void* config);
     // IRtpEncoderListener method
-    virtual void OnRtpPacket(unsigned char* pData, uint32_t nSize);
+    virtual void OnRtpPacket(unsigned char* data, uint32_t nSize);
 
     /**
      * @brief Set the local ip address and port number
@@ -76,17 +78,18 @@
     void GetRtpContext(RtpContextParams& rtpContextParams);
 
 private:
-    bool ProcessAudioData(ImsMediaSubType subtype, uint8_t* pData, uint32_t nDataSize);
-    void ProcessVideoData(ImsMediaSubType subtype, uint8_t* pData, uint32_t nDataSize,
-            uint32_t timestamp, bool mark);
-    void ProcessTextData(ImsMediaSubType subtype, uint8_t* pData, uint32_t nDataSize,
-            uint32_t timestamp, bool mark);
+    void ProcessAudioData(
+            ImsMediaSubType subtype, uint8_t* data, uint32_t size, uint32_t timestamp);
+    void ProcessVideoData(
+            ImsMediaSubType subtype, uint8_t* data, uint32_t size, uint32_t timestamp, bool mark);
+    void ProcessTextData(
+            ImsMediaSubType subtype, uint8_t* data, uint32_t size, uint32_t timestamp, bool mark);
 
     IRtpSession* mRtpSession;
     std::mutex mMutex;
     RtpAddress mLocalAddress;
     RtpAddress mPeerAddress;
-    bool mDTMFMode;
+    bool mDtmfMode;
     bool mMark;
     uint32_t mPrevTimestamp;
     int8_t mSamplingRate;
@@ -101,6 +104,7 @@
     int8_t mRedundantLevel;
     std::list<RtpHeaderExtensionInfo> mListRtpExtension;
     RtpContextParams mRtpContextParams;
+    int32_t mArrivalTime;
 };
 
 #endif
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/SocketReaderNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/SocketReaderNode.h
index 15d13a1..37892bb 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/SocketReaderNode.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/SocketReaderNode.h
@@ -30,7 +30,6 @@
     virtual bool Prepare();
     virtual ImsMediaResult Start();
     virtual void Stop();
-    virtual void ProcessData();
     virtual bool IsRunTime();
     virtual bool IsSourceNode();
     void SetConfig(void* config);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextManager.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextManager.h
index f9e158a..f23ac8f 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextManager.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextManager.h
@@ -62,12 +62,12 @@
     ImsMediaResult openSession(
             const int sessionId, const int rtpFd, const int rtcpFd, TextConfig* config);
     ImsMediaResult closeSession(const int sessionId);
-    virtual bool isOtherSessionActive(const int sessionId);
+    virtual bool deactivateOtherSessionIfActive(const int sessionId);
     ImsMediaResult modifySession(const int sessionId, TextConfig* config);
     virtual void setMediaQualityThreshold(const int sessionId, MediaQualityThreshold* threshold);
     virtual ImsMediaResult sendRtt(const int sessionId, const android::String8* text);
 
-    static TextManager* manager;
+    static TextManager* sManager;
     std::unordered_map<int, std::unique_ptr<TextSession>> mSessions;
     RequestHandler mRequestHandler;
     ResponseHandler mResponseHandler;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextSession.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextSession.h
index 25e05a6..ea1c636 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextSession.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextSession.h
@@ -35,6 +35,13 @@
     virtual void onEvent(int32_t type, uint64_t param1, uint64_t param2);
     ImsMediaResult sendRtt(const android::String8* text);
 
+    /**
+     * @brief move session to inactive. i.e., Rtp Tx and Rtp Rx graphs are stopped
+     *
+     * @return bool false if failed to move session to inactive
+     */
+    bool deactivate();
+
 private:
     TextStreamGraphRtpTx* mGraphRtpTx;
     TextStreamGraphRtpRx* mGraphRtpRx;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/IImsMediaThread.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/IImsMediaThread.h
index 8c2012c..45ffb84 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/IImsMediaThread.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/IImsMediaThread.h
@@ -21,6 +21,9 @@
 
 #define MAX_EVENTHANDLER_NAME 256
 
+// Thread priority value used with SCH_FIFO scheduling policy to set Real-Time priority.
+#define THREAD_PRIORITY_REALTIME 2
+
 /**
  * @class IImsMediaThread
  * @brief Base class of thread
@@ -32,8 +35,8 @@
 public:
     IImsMediaThread();
     virtual ~IImsMediaThread();
-    bool StartThread();
-    void SetAudioThreadPriority(pid_t tid);
+    bool StartThread(const char* name = nullptr);
+    static void SetThreadPriority(pid_t pid, pid_t tid, int priority);
     void StopThread();
     bool IsThreadStopped();
     void* runBase();
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h
index 91c2747..4b04baf 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h
@@ -78,21 +78,21 @@
      * @param event The event type
      * @param sessionId The session id
      */
-    void SendInternalEvent(
+    virtual void SendInternalEvent(
             uint32_t event, uint64_t sessionId, uint64_t paramA = 0, uint64_t paramB = 0);
 
-private:
+protected:
     VideoManager();
     virtual ~VideoManager();
     ImsMediaResult openSession(
             const int sessionId, const int rtpFd, const int rtcpFd, VideoConfig* config);
     ImsMediaResult closeSession(const int sessionId);
-    ImsMediaResult setPreviewSurfaceToSession(const int sessionId, ANativeWindow* surface);
-    ImsMediaResult setDisplaySurfaceToSession(const int sessionId, ANativeWindow* surface);
+    virtual ImsMediaResult setPreviewSurfaceToSession(const int sessionId, ANativeWindow* surface);
+    virtual ImsMediaResult setDisplaySurfaceToSession(const int sessionId, ANativeWindow* surface);
     ImsMediaResult modifySession(const int sessionId, VideoConfig* config);
-    void setMediaQualityThreshold(const int sessionId, MediaQualityThreshold* threshold);
+    virtual void setMediaQualityThreshold(const int sessionId, MediaQualityThreshold* threshold);
 
-    static VideoManager* manager;
+    static VideoManager* sManager;
     std::unordered_map<int, std::unique_ptr<VideoSession>> mSessions;
     RequestHandler mRequestHandler;
     ResponseHandler mResponseHandler;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/BaseNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/BaseNode.cpp
index 97e388c..d3d797f 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/BaseNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/BaseNode.cpp
@@ -30,6 +30,7 @@
         std::make_pair(kNodeIdAudioSource, "AudioSource"),
         std::make_pair(kNodeIdAudioPlayer, "AudioPlayer"),
         std::make_pair(kNodeIdDtmfEncoder, "DtmfEncoder"),
+        std::make_pair(kNodeIdDtmfSender, "DtmfSender"),
         std::make_pair(kNodeIdAudioPayloadEncoder, "AudioPayloadEncoder"),
         std::make_pair(kNodeIdAudioPayloadDecoder, "AudioPayloadDecoder"),
         std::make_pair(kNodeIdVideoSource, "VideoSource"),
@@ -129,6 +130,11 @@
     return RESULT_NOT_SUPPORTED;
 }
 
+bool BaseNode::IsRunTime()
+{
+    return true;
+}
+
 bool BaseNode::IsRunTimeStart()
 {
     return true;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpEncoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpEncoderNode.cpp
index 35b4acb..cbdc703 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpEncoderNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpEncoderNode.cpp
@@ -92,13 +92,6 @@
 void RtcpEncoderNode::Stop()
 {
     IMLOGD0("[Stop]");
-    std::lock_guard<std::mutex> guard(mMutexTimer);
-
-    if (mRtpSession != nullptr)
-    {
-        mRtpSession->StopRtcp();
-    }
-
     if (mTimer != nullptr)
     {
         ImsMediaTimer::TimerStop(mTimer, nullptr);
@@ -106,7 +99,17 @@
         IMLOGD0("[Stop] Rtcp Timer stopped");
     }
 
-    mNodeState = kNodeStateStopped;
+    {
+        std::lock_guard<std::mutex> guard(mMutexTimer);
+        IMLOGD0("[Stop] mutex taken");
+
+        if (mRtpSession != nullptr)
+        {
+            mRtpSession->StopRtcp();
+        }
+
+        mNodeState = kNodeStateStopped;
+    }
 }
 
 bool RtcpEncoderNode::IsRunTime()
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpDecoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpDecoderNode.cpp
index e391952..c36de00 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpDecoderNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpDecoderNode.cpp
@@ -430,7 +430,8 @@
         IMLOGI3("[OnMediaDataInd] media[%d] SSRC changed, [%x] -> [%x]", mMediaType, mReceivingSSRC,
                 ssrc);
         mReceivingSSRC = ssrc;
-        SendDataToRearNode(MEDIASUBTYPE_REFRESHED, nullptr, mReceivingSSRC, 0, 0, 0);
+        SendDataToRearNode(MEDIASUBTYPE_REFRESHED, nullptr, mReceivingSSRC, 0, 0, 0,
+                MEDIASUBTYPE_UNDEFINED, mArrivalTime);
     }
 
     if (mMediaType == IMS_MEDIA_AUDIO &&
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNode.cpp
index 2b2b705..930c5d4 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNode.cpp
@@ -27,7 +27,7 @@
         BaseNode(callback)
 {
     mRtpSession = nullptr;
-    mDTMFMode = false;
+    mDtmfMode = false;
     mMark = false;
     mPrevTimestamp = 0;
     mSamplingRate = 0;
@@ -62,7 +62,6 @@
 ImsMediaResult RtpEncoderNode::Start()
 {
     IMLOGD1("[Start] type[%d]", mMediaType);
-    bool bResetSsrc = false;
 
     if (mRtpPayloadTx == 0 || mRtpPayloadRx == 0)
     {
@@ -94,7 +93,6 @@
     }
     else if (mMediaType == IMS_MEDIA_TEXT)
     {
-        bResetSsrc = true;
         if (mRedundantPayload > 0)
         {
             mRtpSession->SetRtpPayloadParam(mRtpPayloadTx, mRtpPayloadRx, mSamplingRate * 1000,
@@ -113,8 +111,8 @@
         }
     }
 
-    mRtpSession->StartRtp(bResetSsrc);
-    mDTMFMode = false;
+    mRtpSession->StartRtp();
+    mDtmfMode = false;
     mMark = true;
     mPrevTimestamp = 0;
 #ifdef DEBUG_JITTER_GEN_SIMULATION_DELAY
@@ -131,7 +129,6 @@
 void RtpEncoderNode::Stop()
 {
     IMLOGD1("[Stop] type[%d]", mMediaType);
-    std::lock_guard<std::mutex> guard(mMutex);
 
     if (mRtpSession)
     {
@@ -144,49 +141,28 @@
     mNodeState = kNodeStateStopped;
 }
 
-void RtpEncoderNode::ProcessData()
+void RtpEncoderNode::OnDataFromFrontNode(ImsMediaSubType subtype, uint8_t* data, uint32_t size,
+        uint32_t timestamp, bool mark, uint32_t /*seq*/, ImsMediaSubType /*dataType*/,
+        uint32_t arrivalTime)
 {
-    std::lock_guard<std::mutex> guard(mMutex);
-
     if (mNodeState != kNodeStateRunning)
     {
         return;
     }
 
-    ImsMediaSubType subtype;
-    uint8_t* data = nullptr;
-    uint32_t size = 0;
-    uint32_t timestamp = 0;
-    bool mark = false;
-    uint32_t seq = 0;
-    ImsMediaSubType datatype;
-    uint32_t arrivalTime = 0;
-
-    if (GetData(&subtype, &data, &size, &timestamp, &mark, &seq, &datatype, &arrivalTime))
+    if (mMediaType == IMS_MEDIA_AUDIO)
     {
-        if (mMediaType == IMS_MEDIA_AUDIO)
-        {
-            if (!ProcessAudioData(subtype, data, size))
-            {
-                return;
-            }
-        }
-        else if (mMediaType == IMS_MEDIA_VIDEO)
-        {
-            ProcessVideoData(subtype, data, size, timestamp, mark);
-        }
-        else if (mMediaType == IMS_MEDIA_TEXT)
-        {
-            ProcessTextData(subtype, data, size, timestamp, mark);
-        }
-
-        DeleteData();
+        mArrivalTime = arrivalTime;
+        ProcessAudioData(subtype, data, size, timestamp);
     }
-}
-
-bool RtpEncoderNode::IsRunTime()
-{
-    return false;
+    else if (mMediaType == IMS_MEDIA_VIDEO)
+    {
+        ProcessVideoData(subtype, data, size, timestamp, mark);
+    }
+    else if (mMediaType == IMS_MEDIA_TEXT)
+    {
+        ProcessTextData(subtype, data, size, timestamp, mark);
+    }
 }
 
 bool RtpEncoderNode::IsSourceNode()
@@ -292,7 +268,8 @@
 
 void RtpEncoderNode::OnRtpPacket(unsigned char* data, uint32_t nSize)
 {
-    SendDataToRearNode(MEDIASUBTYPE_RTPPACKET, data, nSize, 0, 0, 0);
+    SendDataToRearNode(
+            MEDIASUBTYPE_RTPPACKET, data, nSize, 0, 0, 0, MEDIASUBTYPE_UNDEFINED, mArrivalTime);
 }
 
 void RtpEncoderNode::SetLocalAddress(const RtpAddress& address)
@@ -437,42 +414,37 @@
     delete[] extensionData;
 }
 
-bool RtpEncoderNode::ProcessAudioData(ImsMediaSubType subtype, uint8_t* data, uint32_t size)
+void RtpEncoderNode::ProcessAudioData(
+        ImsMediaSubType subtype, uint8_t* data, uint32_t size, uint32_t timestamp)
 {
-    uint32_t currentTimestamp;
+    std::lock_guard<std::mutex> guard(mMutex);
+
     uint32_t timeDiff;
     uint32_t timestampDiff;
 
     if (subtype == MEDIASUBTYPE_DTMFSTART)
     {
         IMLOGD0("[ProcessAudioData] SetDTMF mode true");
-        mDTMFMode = true;
+        mDtmfMode = true;
         mMark = true;
     }
     else if (subtype == MEDIASUBTYPE_DTMFEND)
     {
         IMLOGD0("[ProcessAudioData] SetDTMF mode false");
-        mDTMFMode = false;
+        mDtmfMode = false;
         mMark = true;
     }
     else if (subtype == MEDIASUBTYPE_DTMF_PAYLOAD)
     {
-        if (mDTMFMode)
+        if (mDtmfMode)
         {
-            currentTimestamp = ImsMediaTimer::GetTimeInMilliSeconds();
-            timeDiff = currentTimestamp - mPrevTimestamp;
-
-            if (timeDiff < 20)
-            {
-                return false;
-            }
-
-            mMark ? mDtmfTimestamp = currentTimestamp : timeDiff = 0;
-            mPrevTimestamp = currentTimestamp;
+            timeDiff = timestamp - mPrevTimestamp;
+            mMark ? mDtmfTimestamp = timestamp : timeDiff = 0;
+            mPrevTimestamp = timestamp;
             timestampDiff = timeDiff * mSamplingRate;
 
             IMLOGD_PACKET3(IM_PACKET_LOG_RTP,
-                    "[ProcessAudioData] dtmf payload, size[%u], TS[%u], diff[%d]", size,
+                    "[ProcessAudioData] dtmf payload, size[%u], TS[%u], diff[%u]", size,
                     mDtmfTimestamp, timestampDiff);
             mRtpSession->SendRtpPacket(
                     mRtpTxDtmfPayload, data, size, mDtmfTimestamp, mMark, timestampDiff);
@@ -481,32 +453,10 @@
     }
     else  // MEDIASUBTYPE_RTPPAYLOAD
     {
-        if (mDTMFMode == false)
+        if (!mDtmfMode)
         {
-            currentTimestamp = ImsMediaTimer::GetTimeInMilliSeconds();
-
-            if (mPrevTimestamp == 0)
-            {
-                timeDiff = 0;
-                mPrevTimestamp = currentTimestamp;
-            }
-            else
-            {
-                timeDiff = ((currentTimestamp - mPrevTimestamp) + 5) / 20 * 20;
-
-                if (timeDiff > 20)
-                {
-                    mPrevTimestamp = currentTimestamp;
-                }
-                else if (timeDiff == 0)
-                {
-                    return false;
-                }
-                else
-                {
-                    mPrevTimestamp += timeDiff;
-                }
-            }
+            timeDiff = mPrevTimestamp == 0 ? 0 : ((timestamp - mPrevTimestamp) + 10) / 20 * 20;
+            mPrevTimestamp = timestamp;
 
             RtpPacket* packet = new RtpPacket();
             packet->rtpDataType = kRtpDataTypeNormal;
@@ -514,19 +464,19 @@
                     kCollectPacketInfo, kStreamRtpTx, reinterpret_cast<uint64_t>(packet));
 
             timestampDiff = timeDiff * mSamplingRate;
-            IMLOGD_PACKET3(IM_PACKET_LOG_RTP, "[ProcessAudioData] size[%u], TS[%u], diff[%d]", size,
-                    currentTimestamp, timestampDiff);
+            IMLOGD_PACKET3(IM_PACKET_LOG_RTP, "[ProcessAudioData] size[%u], TS[%u], diff[%u]", size,
+                    timestamp, timestampDiff);
 
             if (!mListRtpExtension.empty())
             {
-                mRtpSession->SendRtpPacket(mRtpPayloadTx, data, size, currentTimestamp, mMark,
+                mRtpSession->SendRtpPacket(mRtpPayloadTx, data, size, timestamp, mMark,
                         timestampDiff, &mListRtpExtension.front());
                 mListRtpExtension.pop_front();
             }
             else
             {
                 mRtpSession->SendRtpPacket(
-                        mRtpPayloadTx, data, size, currentTimestamp, mMark, timestampDiff);
+                        mRtpPayloadTx, data, size, timestamp, mMark, timestampDiff);
             }
 
             if (mMark)
@@ -535,8 +485,6 @@
             }
         }
     }
-
-    return true;
 }
 
 void RtpEncoderNode::ProcessVideoData(
@@ -573,16 +521,7 @@
             "[ProcessTextData] subtype[%d], size[%d], timestamp[%d], mark[%d]", subtype, size,
             timestamp, mark);
 
-    uint32_t timeDiff;
-
-    if (mMark == true)
-    {
-        timeDiff = 0;
-    }
-    else
-    {
-        timeDiff = timestamp - mPrevTimestamp;
-    }
+    uint32_t timeDiff = mMark ? 0 : timestamp - mPrevTimestamp;
 
     if (subtype == MEDIASUBTYPE_BITSTREAM_T140)
     {
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/SocketReaderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/SocketReaderNode.cpp
index 549056d..4bd392b 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/SocketReaderNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/SocketReaderNode.cpp
@@ -53,8 +53,6 @@
 
 ImsMediaResult SocketReaderNode::Start()
 {
-    ClearDataQueue();  // clear the old data stacked
-
     if (mSocketOpened)
     {
         IMLOGD0("[Start] opened already");
@@ -74,34 +72,13 @@
 void SocketReaderNode::Stop()
 {
     IMLOGD2("[Stop] media[%d], protocolType[%d]", mMediaType, mProtocolType);
+    std::lock_guard<std::mutex> guard(mMutex);
     mNodeState = kNodeStateStopped;
 }
 
-void SocketReaderNode::ProcessData()
-{
-    uint8_t* data = nullptr;
-    uint32_t dataSize = 0;
-    uint32_t timeStamp = 0;
-    bool bMark = false;
-    uint32_t seqNum = 0;
-    ImsMediaSubType subtype;
-    ImsMediaSubType dataType;
-    uint32_t arrivalTime;
-
-    while (GetData(
-            &subtype, &data, &dataSize, &timeStamp, &bMark, &seqNum, &dataType, &arrivalTime))
-    {
-        IMLOGD_PACKET3(IM_PACKET_LOG_SOCKET, "[ProcessData] media[%d], size[%d], arrivalTime[%u]",
-                mMediaType, dataSize, arrivalTime);
-        SendDataToRearNode(MEDIASUBTYPE_UNDEFINED, reinterpret_cast<uint8_t*>(data), dataSize,
-                timeStamp, bMark, seqNum, dataType, arrivalTime);
-        DeleteData();
-    }
-}
-
 bool SocketReaderNode::IsRunTime()
 {
-    return false;
+    return true;
 }
 
 bool SocketReaderNode::IsSourceNode()
@@ -198,27 +175,22 @@
 
 void SocketReaderNode::OnReadDataFromSocket()
 {
-    IMLOGD_PACKET1(IM_PACKET_LOG_SOCKET, "[OnReadDataFromSocket] media[%d]", mMediaType);
     std::lock_guard<std::mutex> guard(mMutex);
 
-    // prevent infinite frame stacked in the queue
-    if (mDataQueue.GetCount() > MAX_BUFFER_QUEUE)
-    {
-        mDataQueue.Delete();
-    }
-
     if (mSocketOpened && mSocket != nullptr)
     {
-        int nLen = mSocket->ReceiveFrom(mBuffer, DEFAULT_MTU);
+        int len = mSocket->ReceiveFrom(mBuffer, DEFAULT_MTU);
 
-        if (nLen > 0)
+        if (len > 0)
         {
-            IMLOGD_PACKET3(IM_PACKET_LOG_SOCKET,
-                    "[OnReadDataFromSocket] media[%d], data size[%d], queue size[%d]", mMediaType,
-                    nLen, GetDataCount());
+            IMLOGD_PACKET2(IM_PACKET_LOG_SOCKET, "[OnReadDataFromSocket] media[%d], data size[%d]",
+                    mMediaType, len);
 
-            OnDataFromFrontNode(MEDIASUBTYPE_UNDEFINED, mBuffer, nLen, 0, 0, 0,
-                    MEDIASUBTYPE_UNDEFINED, ImsMediaTimer::GetTimeInMilliSeconds());
+            if (mNodeState == kNodeStateRunning)
+            {
+                SendDataToRearNode(MEDIASUBTYPE_UNDEFINED, mBuffer, len, 0, 0, 0,
+                        MEDIASUBTYPE_UNDEFINED, ImsMediaTimer::GetTimeInMilliSeconds());
+            }
         }
     }
 }
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/SocketWriterNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/SocketWriterNode.cpp
index f2437ea..1947869 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/SocketWriterNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/SocketWriterNode.cpp
@@ -16,6 +16,7 @@
 
 #include <SocketWriterNode.h>
 #include <ImsMediaTrace.h>
+#include <ImsMediaTimer.h>
 
 SocketWriterNode::SocketWriterNode(BaseSessionCallback* callback) :
         BaseNode(callback)
@@ -140,21 +141,18 @@
 }
 
 void SocketWriterNode::OnDataFromFrontNode(ImsMediaSubType subtype, uint8_t* pData,
-        uint32_t nDataSize, uint32_t nTimestamp, bool bMark, uint32_t nSeqNum,
-        ImsMediaSubType nDataType, uint32_t arrivalTime)
+        uint32_t nDataSize, uint32_t nTimestamp, bool /*bMark*/, uint32_t nSeqNum,
+        ImsMediaSubType /*nDataType*/, uint32_t arrivalTime)
 {
-    (void)nDataType;
-    (void)bMark;
-    (void)arrivalTime;
-
     if (mDisableSocket == true && subtype != MEDIASUBTYPE_RTCPPACKET_BYE)
     {
         IMLOGW3("[OnDataFromFrontNode] media[%d] subtype[%d] socket is disabled, bytes[%d]",
                 mMediaType, subtype, nDataSize);
     }
 
-    IMLOGD_PACKET3(IM_PACKET_LOG_SOCKET, "[OnDataFromFrontNode] TS[%d], SeqNum[%u], size[%u]",
-            nTimestamp, nSeqNum, nDataSize);
+    IMLOGD_PACKET4(IM_PACKET_LOG_SOCKET,
+            "[OnDataFromFrontNode] TS[%d], SeqNum[%u], size[%u], timeDiff[%d]", nTimestamp, nSeqNum,
+            nDataSize, arrivalTime != 0 ? ImsMediaTimer::GetTimeInMilliSeconds() - arrivalTime : 0);
 
     if (mSocket == nullptr)
     {
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManager.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManager.cpp
index 8bff99b..54ca008 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManager.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManager.cpp
@@ -19,7 +19,7 @@
 #include <ImsMediaNetworkUtil.h>
 
 using namespace android;
-TextManager* TextManager::manager;
+TextManager* TextManager::sManager;
 
 TextManager::TextManager()
 {
@@ -31,17 +31,17 @@
 {
     mRequestHandler.Deinit();
     mResponseHandler.Deinit();
-    manager = nullptr;
+    sManager = nullptr;
 }
 
 TextManager* TextManager::getInstance()
 {
-    if (manager == nullptr)
+    if (sManager == nullptr)
     {
-        manager = new TextManager();
+        sManager = new TextManager();
     }
 
-    return manager;
+    return sManager;
 }
 
 int TextManager::getState(int sessionId)
@@ -111,15 +111,15 @@
     {
         if ((config->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE ||
                     config->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY ||
-                    config->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_ONLY) &&
-                isOtherSessionActive(sessionId))
+                    config->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_ONLY))
         {
-            return RESULT_NO_RESOURCES;
+            if (!deactivateOtherSessionIfActive(sessionId))
+            {
+                return RESULT_NO_RESOURCES;
+            }
         }
-        else
-        {
-            return (session->second)->startGraph(config);
-        }
+
+        return (session->second)->startGraph(config);
     }
     else
     {
@@ -224,6 +224,12 @@
 {
     IMLOGI4("[processEvent] event[%d], sessionId[%d], paramA[%d], paramB[%d]", event, sessionId,
             paramA, paramB);
+
+    if (sManager == nullptr)
+    {
+        return;
+    }
+
     ImsMediaResult result = RESULT_SUCCESS;
 
     switch (event)
@@ -234,7 +240,7 @@
             if (param != nullptr)
             {
                 TextConfig* pConfig = reinterpret_cast<TextConfig*>(param->mConfig);
-                result = TextManager::getInstance()->openSession(
+                result = sManager->openSession(
                         static_cast<int>(sessionId), param->rtpFd, param->rtcpFd, pConfig);
 
                 if (result == RESULT_SUCCESS)
@@ -263,8 +269,7 @@
         }
         break;
         case kTextCloseSession:
-            if (TextManager::getInstance()->closeSession(static_cast<int>(sessionId)) ==
-                    RESULT_SUCCESS)
+            if (sManager->closeSession(static_cast<int>(sessionId)) == RESULT_SUCCESS)
             {
                 ImsMediaEventHandler::SendEvent(
                         "TEXT_RESPONSE_EVENT", kTextSessionClosed, sessionId, 0, 0);
@@ -273,7 +278,7 @@
         case kTextModifySession:
         {
             TextConfig* config = reinterpret_cast<TextConfig*>(paramA);
-            result = TextManager::getInstance()->modifySession(static_cast<int>(sessionId), config);
+            result = sManager->modifySession(static_cast<int>(sessionId), config);
             ImsMediaEventHandler::SendEvent(
                     "TEXT_RESPONSE_EVENT", kTextModifySessionResponse, sessionId, result, paramA);
         }
@@ -284,8 +289,7 @@
 
             if (threshold != nullptr)
             {
-                TextManager::getInstance()->setMediaQualityThreshold(
-                        static_cast<int>(sessionId), threshold);
+                sManager->setMediaQualityThreshold(static_cast<int>(sessionId), threshold);
                 delete threshold;
             }
         }
@@ -296,7 +300,7 @@
 
             if (text != nullptr)
             {
-                TextManager::getInstance()->sendRtt(static_cast<int>(sessionId), text);
+                sManager->sendRtt(static_cast<int>(sessionId), text);
                 delete text;
             }
         }
@@ -311,6 +315,12 @@
 {
     IMLOGI4("[processEvent] event[%d], sessionId[%d], paramA[%d], paramB[%d]", event, sessionId,
             paramA, paramB);
+
+    if (sManager == nullptr)
+    {
+        return;
+    }
+
     android::Parcel parcel;
     switch (event)
     {
@@ -325,7 +335,7 @@
                 parcel.writeInt32(static_cast<int>(paramA));
             }
 
-            TextManager::getInstance()->sendResponse(sessionId, parcel);
+            sManager->sendResponse(sessionId, parcel);
             break;
         case kTextModifySessionResponse:  // fall through
         {
@@ -336,7 +346,7 @@
             if (config != nullptr)
             {
                 config->writeToParcel(&parcel);
-                TextManager::getInstance()->sendResponse(sessionId, parcel);
+                sManager->sendResponse(sessionId, parcel);
                 delete config;
             }
         }
@@ -345,7 +355,7 @@
             parcel.writeInt32(event);
             parcel.writeInt32(static_cast<int>(paramA));  // type
             parcel.writeInt32(static_cast<int>(paramB));  // duration
-            TextManager::getInstance()->sendResponse(sessionId, parcel);
+            sManager->sendResponse(sessionId, parcel);
             break;
         case kTextRttReceived:
         {
@@ -356,7 +366,7 @@
             {
                 String16 rttText(*text);
                 parcel.writeString16(rttText);
-                TextManager::getInstance()->sendResponse(sessionId, parcel);
+                sManager->sendResponse(sessionId, parcel);
                 delete text;
             }
         }
@@ -364,14 +374,14 @@
         case kTextSessionClosed:
             parcel.writeInt32(event);
             parcel.writeInt32(static_cast<int>(sessionId));
-            TextManager::getInstance()->sendResponse(sessionId, parcel);
+            sManager->sendResponse(sessionId, parcel);
             break;
         default:
             break;
     }
 }
 
-bool TextManager::isOtherSessionActive(const int sessionId)
+bool TextManager::deactivateOtherSessionIfActive(const int sessionId)
 {
     for (auto const& session : mSessions)
     {
@@ -381,9 +391,15 @@
             if (state == kSessionStateActive)
             {
                 IMLOGE1("[modifySession] Another session id[%d] is active", session.first);
-                return true;
+                if ((session.second)->deactivate())
+                {
+                    IMLOGI1("[modifySession] Moved session id[%d] to inactive", session.first);
+                    return true;
+                }
+                IMLOGE1("[modifySession] Failed to move session id[%d] to inactive", session.first);
+                return false;
             }
         }
     }
-    return false;
+    return true;
 }
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextSession.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextSession.cpp
index 2c3cf04..da7664b 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextSession.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextSession.cpp
@@ -229,4 +229,38 @@
         default:
             break;
     }
+}
+
+bool TextSession::deactivate()
+{
+    IMLOGI0("[deactivate]");
+
+    if (mGraphRtpTx != nullptr)
+    {
+        if (mGraphRtpTx->getState() == kStreamStateRunning)
+        {
+            mGraphRtpTx->stop();
+        }
+
+        delete mGraphRtpTx;
+        mGraphRtpTx = nullptr;
+    }
+
+    if (mGraphRtpRx != nullptr)
+    {
+        if (mGraphRtpRx->getState() == kStreamStateRunning)
+        {
+            mGraphRtpRx->stop();
+        }
+
+        delete mGraphRtpRx;
+        mGraphRtpRx = nullptr;
+    }
+
+    if (getState() == kSessionStateActive)
+    {
+        return false;
+    }
+
+    return true;
 }
\ No newline at end of file
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/IImsMediaThread.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/IImsMediaThread.cpp
index baabe45..20551fa 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/IImsMediaThread.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/IImsMediaThread.cpp
@@ -17,6 +17,9 @@
 #include <IImsMediaThread.h>
 #include <ImsMediaTrace.h>
 #include <thread>
+#include <mediautils/SchedulingPolicyService.h>
+
+#define MAX_THREAD_NAME_LEN 16
 
 extern void setAudioThreadPriority(int threadId);
 
@@ -39,19 +42,34 @@
     return thread->runBase();
 }
 
-bool IImsMediaThread::StartThread()
+bool IImsMediaThread::StartThread(const char* name)
 {
     std::lock_guard<std::mutex> guard(mThreadMutex);
     mThreadStopped = false;
 
     std::thread t1(&runThread, this);
+    if (name)
+    {
+        if (strlen(name) >= MAX_THREAD_NAME_LEN)
+        {
+            char shortname[MAX_THREAD_NAME_LEN];
+            strncpy(shortname, name, MAX_THREAD_NAME_LEN - 1);
+            pthread_setname_np(t1.native_handle(), shortname);
+        }
+        else
+        {
+            pthread_setname_np(t1.native_handle(), name);
+        }
+    }
     t1.detach();
     return true;
 }
 
-void IImsMediaThread::SetAudioThreadPriority(pid_t tid)
+void IImsMediaThread::SetThreadPriority(pid_t pid, pid_t tid, int priority)
 {
-    setAudioThreadPriority(tid);
+    const int err =
+            android::requestPriority(pid, tid, priority, false /*isForApp*/, true /*asynchronous*/);
+    IMLOGD3("[SetThreadPriority] tid:%u, returned:%d. Err: %s", tid, err, strerror(errno));
 }
 
 void IImsMediaThread::StopThread()
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaEventHandler.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaEventHandler.cpp
index f03c559..bdd83b9 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaEventHandler.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaEventHandler.cpp
@@ -32,7 +32,7 @@
     mbTerminate = false;
     gListEventHandler.push_back(this);
     IMLOGD1("[Init] %s", mName);
-    StartThread();
+    StartThread("ImsMediaEventHandler");
 }
 
 void ImsMediaEventHandler::Deinit()
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaSocket.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaSocket.cpp
index e8ea46b..1aa317b 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaSocket.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaSocket.cpp
@@ -30,6 +30,7 @@
 #include <ImsMediaSocket.h>
 #include <ImsMediaTrace.h>
 #include <ImsMediaNetworkUtil.h>
+#include <IImsMediaThread.h>
 
 // static valuable
 std::list<ImsMediaSocket*> ImsMediaSocket::slistRxSocket;
@@ -542,6 +543,7 @@
     static fd_set TmpExcepfds;
     int nMaxSD;
     IMLOGD0("[SocketMonitorThread] enter");
+    IImsMediaThread::SetThreadPriority(getpid(), gettid(), THREAD_PRIORITY_REALTIME);
     nMaxSD = SetSocketFD(&ReadFds, &WriteFds, &ExceptFds);
 
     for (;;)
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaTimer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaTimer.cpp
index 287a358..143e64f 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaTimer.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaTimer.cpp
@@ -37,9 +37,9 @@
     bool mTerminateThread;
     uint32_t mStartTimeSec;
     uint32_t mStartTimeMSec;
+    std::mutex mMutex;
 };
 
-static std::mutex gMutex;
 static std::mutex gMutexList;
 static std::list<TimerInstance*> gTimerList;
 
@@ -135,21 +135,19 @@
                     pInstance->mStartTimeMSec = nCurrTimeMSec;
                 }
 
-                gMutex.lock();
+                {  // Critical section
+                    std::lock_guard<std::mutex> guard(pInstance->mMutex);
+                    if (pInstance->mTerminateThread)
+                    {
+                        break;
+                    }
 
-                if (pInstance->mTerminateThread)
-                {
-                    gMutex.unlock();
-                    break;
+                    if (pInstance->mTimerCb)
+                    {
+                        pInstance->mTimerCb(pInstance, pInstance->mUserData);
+                    }
                 }
 
-                if (pInstance->mTimerCb)
-                {
-                    pInstance->mTimerCb(pInstance, pInstance->mUserData);
-                }
-
-                gMutex.unlock();
-
                 if (pInstance->mRepeat == false)
                 {
                     break;
@@ -162,7 +160,7 @@
 
     if (pInstance != nullptr)
     {
-        free(pInstance);
+        delete pInstance;
         pInstance = nullptr;
     }
 
@@ -173,7 +171,7 @@
         uint32_t nDuration, bool bRepeat, fn_TimerCb pTimerCb, void* pUserData)
 {
     struct timeval tp;
-    TimerInstance* pInstance = reinterpret_cast<TimerInstance*>(malloc(sizeof(TimerInstance)));
+    TimerInstance* pInstance = new TimerInstance;
 
     if (pInstance == nullptr)
     {
@@ -186,7 +184,7 @@
     pInstance->mUserData = pUserData;
     pInstance->mTerminateThread = false;
 
-    IMLOGD3("[TimerStart] Duratation[%u], bRepeat[%d], pUserData[%x]", pInstance->mDuration,
+    IMLOGD3("[TimerStart] Duration[%u], bRepeat[%d], pUserData[%x]", pInstance->mDuration,
             bRepeat, pInstance->mUserData);
 
     if (gettimeofday(&tp, nullptr) != -1)
@@ -196,7 +194,7 @@
     }
     else
     {
-        free(pInstance);
+        delete pInstance;
         return nullptr;
     }
 
@@ -211,6 +209,7 @@
 {
     TimerInstance* pInstance = reinterpret_cast<TimerInstance*>(hTimer);
 
+    IMLOGD1("[TimerStop] pInstance[%x]", pInstance);
     if (pInstance == nullptr)
     {
         return false;
@@ -221,15 +220,18 @@
         return false;
     }
 
-    gMutex.lock();  // just wait until timer callback returns...
-    pInstance->mTerminateThread = true;
-
-    if (ppUserData)
     {
-        *ppUserData = pInstance->mUserData;
+        std::lock_guard<std::mutex> guard(pInstance->mMutex);
+        IMLOGD1("[TimerStop] mutex taken pInstance[%x]", pInstance);
+
+        pInstance->mTerminateThread = true;
+
+        if (ppUserData)
+        {
+            *ppUserData = pInstance->mUserData;
+        }
     }
 
-    gMutex.unlock();
     return true;
 }
 
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp
index 4652511..0ad3439 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp
@@ -19,7 +19,7 @@
 #include <ImsMediaNetworkUtil.h>
 
 using namespace android;
-VideoManager* VideoManager::manager;
+VideoManager* VideoManager::sManager;
 
 VideoManager::VideoManager()
 {
@@ -31,17 +31,17 @@
 {
     mRequestHandler.Deinit();
     mResponseHandler.Deinit();
-    manager = nullptr;
+    sManager = nullptr;
 }
 
 VideoManager* VideoManager::getInstance()
 {
-    if (manager == nullptr)
+    if (sManager == nullptr)
     {
-        manager = new VideoManager();
+        sManager = new VideoManager();
     }
 
-    return manager;
+    return sManager;
 }
 
 int VideoManager::getState(int sessionId)
@@ -261,6 +261,11 @@
             paramA, paramB);
     ImsMediaResult result = RESULT_SUCCESS;
 
+    if (sManager == nullptr)
+    {
+        return;
+    }
+
     switch (event)
     {
         case kVideoOpenSession:
@@ -270,7 +275,7 @@
             if (param != nullptr)
             {
                 VideoConfig* pConfig = reinterpret_cast<VideoConfig*>(param->mConfig);
-                result = VideoManager::getInstance()->openSession(
+                result = sManager->openSession(
                         static_cast<int>(sessionId), param->rtpFd, param->rtcpFd, pConfig);
 
                 if (result == RESULT_SUCCESS)
@@ -299,26 +304,24 @@
         }
         break;
         case kVideoCloseSession:
-            if (VideoManager::getInstance()->closeSession(static_cast<int>(sessionId)) ==
-                    RESULT_SUCCESS)
+            if (sManager->closeSession(static_cast<int>(sessionId)) == RESULT_SUCCESS)
             {
                 ImsMediaEventHandler::SendEvent(
                         "VIDEO_RESPONSE_EVENT", kVideoSessionClosed, sessionId, 0, 0);
             }
             break;
         case kVideoSetPreviewSurface:
-            VideoManager::getInstance()->setPreviewSurfaceToSession(
+            sManager->setPreviewSurfaceToSession(
                     static_cast<int>(sessionId), reinterpret_cast<ANativeWindow*>(paramA));
             break;
         case kVideoSetDisplaySurface:
-            VideoManager::getInstance()->setDisplaySurfaceToSession(
+            sManager->setDisplaySurfaceToSession(
                     static_cast<int>(sessionId), reinterpret_cast<ANativeWindow*>(paramA));
             break;
         case kVideoModifySession:
         {
             VideoConfig* config = reinterpret_cast<VideoConfig*>(paramA);
-            result =
-                    VideoManager::getInstance()->modifySession(static_cast<int>(sessionId), config);
+            result = sManager->modifySession(static_cast<int>(sessionId), config);
             ImsMediaEventHandler::SendEvent(
                     "VIDEO_RESPONSE_EVENT", kVideoModifySessionResponse, sessionId, result, paramA);
         }
@@ -332,8 +335,7 @@
 
             if (threshold != nullptr)
             {
-                VideoManager::getInstance()->setMediaQualityThreshold(
-                        static_cast<int>(sessionId), threshold);
+                sManager->setMediaQualityThreshold(static_cast<int>(sessionId), threshold);
                 delete threshold;
             }
         }
@@ -346,7 +348,7 @@
         case kRequestVideoSendTmmbr:
         case kRequestVideoSendTmmbn:
         case kRequestRoundTripTimeDelayUpdate:
-            VideoManager::getInstance()->SendInternalEvent(event, sessionId, paramA, paramB);
+            sManager->SendInternalEvent(event, sessionId, paramA, paramB);
             break;
         default:
             break;
@@ -358,7 +360,14 @@
 {
     IMLOGI4("[processEvent] event[%d], sessionId[%d], paramA[%d], paramB[%d]", event, sessionId,
             paramA, paramB);
+
+    if (sManager == nullptr)
+    {
+        return;
+    }
+
     android::Parcel parcel;
+
     switch (event)
     {
         case kVideoOpenSessionSuccess:
@@ -372,7 +381,7 @@
                 parcel.writeInt32(static_cast<int>(paramA));
             }
 
-            VideoManager::getInstance()->sendResponse(sessionId, parcel);
+            sManager->sendResponse(sessionId, parcel);
             break;
         case kVideoModifySessionResponse:  // fall through
         {
@@ -383,20 +392,20 @@
             if (config != nullptr)
             {
                 config->writeToParcel(&parcel);
-                VideoManager::getInstance()->sendResponse(sessionId, parcel);
+                sManager->sendResponse(sessionId, parcel);
                 delete config;
             }
         }
         break;
         case kVideoFirstMediaPacketInd:
             parcel.writeInt32(event);
-            VideoManager::getInstance()->sendResponse(sessionId, parcel);
+            sManager->sendResponse(sessionId, parcel);
             break;
         case kVideoPeerDimensionChanged:
             parcel.writeInt32(event);
             parcel.writeInt32(static_cast<int>(paramA));
             parcel.writeInt32(static_cast<int>(paramB));
-            VideoManager::getInstance()->sendResponse(sessionId, parcel);
+            sManager->sendResponse(sessionId, parcel);
             break;
         case kVideoRtpHeaderExtensionInd:
             // TODO : add implementation
@@ -405,17 +414,17 @@
         case kVideoBitrateInd:
             parcel.writeInt32(event);
             parcel.writeInt32(static_cast<int>(paramA));
-            VideoManager::getInstance()->sendResponse(sessionId, parcel);
+            sManager->sendResponse(sessionId, parcel);
             break;
         case kVideoDataUsageInd:
             parcel.writeInt32(event);
             parcel.writeInt64(static_cast<int>(paramA));
-            VideoManager::getInstance()->sendResponse(sessionId, parcel);
+            sManager->sendResponse(sessionId, parcel);
             break;
         case kVideoSessionClosed:
             parcel.writeInt32(event);
             parcel.writeInt32(static_cast<int>(sessionId));
-            VideoManager::getInstance()->sendResponse(sessionId, parcel);
+            sManager->sendResponse(sessionId, parcel);
             break;
         default:
             break;
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 ba43d0a..67c5684 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
@@ -249,7 +249,7 @@
             break;
         case kImsMediaEventFirstPacketReceived:
             ImsMediaEventHandler::SendEvent(
-                    "VIDEO_RESPONSE_EVENT", kVideoFirstMediaPacketInd, param1, param2);
+                    "VIDEO_RESPONSE_EVENT", kVideoFirstMediaPacketInd, mSessionId, param1, param2);
             break;
         case kImsMediaEventResolutionChanged:
             ImsMediaEventHandler::SendEvent(
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaVideoRenderer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaVideoRenderer.cpp
index 475425b..f3fff62 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaVideoRenderer.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaVideoRenderer.cpp
@@ -80,13 +80,13 @@
 bool ImsMediaVideoRenderer::Start()
 {
     IMLOGD0("[Start]");
-    mMutex.lock();
     mFormat = AMediaFormat_new();
     AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_WIDTH, mWidth);
     AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_HEIGHT, mHeight);
 
     char kMimeType[128] = {'\0'};
     sprintf(kMimeType, "video/avc");
+
     if (mCodecType == kVideoCodecHevc)
     {
         sprintf(kMimeType, "video/hevc");
@@ -99,6 +99,7 @@
     AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_ROTATION, mFarOrientationDegree);
 
     mCodec = AMediaCodec_createDecoderByType(kMimeType);
+
     if (mCodec == nullptr)
     {
         IMLOGE0("[Start] Unable to create decoder");
@@ -111,6 +112,7 @@
     }
 
     media_status_t err = AMediaCodec_configure(mCodec, mFormat, mWindow, nullptr, 0);
+
     if (err != AMEDIA_OK)
     {
         IMLOGE1("[Start] configure error[%d]", err);
@@ -122,6 +124,7 @@
     }
 
     err = AMediaCodec_start(mCodec);
+
     if (err != AMEDIA_OK)
     {
         IMLOGE1("[Start] codec start[%d]", err);
@@ -133,7 +136,6 @@
     }
 
     mStopped = false;
-    mMutex.unlock();
     std::thread t1(&ImsMediaVideoRenderer::processBuffers, this);
     t1.detach();
     return true;
@@ -178,12 +180,17 @@
 
     IMLOGD_PACKET2(IM_PACKET_LOG_VIDEO, "[OnDataFrame] frame size[%u], list[%d]", size,
             mFrameDatas.size());
-    std::lock_guard<std::mutex> guard(mMutex);
-    if (mCodec == nullptr)
+
+    mMutex.lock();
+
+    if (mStopped)
     {
+        mMutex.unlock();
         return;
     }
 
+    mMutex.unlock();
+
     mFrameDatas.push_back(new FrameData(buffer, size, timestamp, isConfigFrame));
 }
 
@@ -197,11 +204,13 @@
     while (true)
     {
         mMutex.lock();
+
         if (mStopped)
         {
             mMutex.unlock();
             break;
         }
+
         mMutex.unlock();
 
         if (mFrameDatas.size() == 0)
diff --git a/tests/native/Android.bp b/tests/native/Android.bp
index 255fa57..cf72ff1 100644
--- a/tests/native/Android.bp
+++ b/tests/native/Android.bp
@@ -23,6 +23,8 @@
     export_include_dirs: [
         "service/src/com/android/telephony/imsmedia/lib/libimsmedia/include",
         "service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/audio",
+        "service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/video",
+        "service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/text",
     ],
 }
 
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/AudioConfigTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/AudioConfigTest.cpp
index 3beca9f..e390835 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/AudioConfigTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/AudioConfigTest.cpp
@@ -130,7 +130,8 @@
 
 TEST_F(AudioConfigTest, TestAssign)
 {
-    AudioConfig testConfig = config1;
+    AudioConfig testConfig;
+    testConfig = config1;
     EXPECT_EQ(config1, testConfig);
 
     AudioConfig* testConfig2 = new AudioConfig(config1);
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/CallQualityTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/CallQualityTest.cpp
index 5fcc6f9..4cad123 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/CallQualityTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/CallQualityTest.cpp
@@ -93,7 +93,8 @@
 
 TEST_F(CallQualityTest, TestAssign)
 {
-    CallQuality testQuality = quality1;
+    CallQuality testQuality;
+    testQuality = quality1;
     EXPECT_EQ(quality1, testQuality);
 }
 
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
index c32c2d2..aa8aed0 100644
--- 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
@@ -62,7 +62,8 @@
 
 TEST_F(MediaQualityStatusTest, TestAssign)
 {
-    MediaQualityStatus status2 = status;
+    MediaQualityStatus status2;
+    status2 = status;
     EXPECT_EQ(status, status2);
 }
 
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 3349446..a68db0a 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
@@ -74,7 +74,8 @@
 
 TEST_F(MediaQualityThresholdTest, TestAssign)
 {
-    MediaQualityThreshold threshold2 = threshold;
+    MediaQualityThreshold threshold2;
+    threshold2 = threshold;
     EXPECT_EQ(threshold, threshold2);
 }
 
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/TextConfigTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/TextConfigTest.cpp
index 00f4cd6..793bdf0 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/TextConfigTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/TextConfigTest.cpp
@@ -96,7 +96,8 @@
 
 TEST_F(TextConfigTest, TestAssign)
 {
-    TextConfig testConfig = config1;
+    TextConfig testConfig;
+    testConfig = config1;
     EXPECT_EQ(config1, testConfig);
 
     TextConfig* testConfig2 = new TextConfig(config1);
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/VideoConfigTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/VideoConfigTest.cpp
index f18d081..66ba3b1 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/VideoConfigTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/VideoConfigTest.cpp
@@ -145,7 +145,8 @@
 
 TEST_F(VideoConfigTest, TestAssign)
 {
-    VideoConfig testConfig = config1;
+    VideoConfig testConfig;
+    testConfig = config1;
     EXPECT_EQ(config1, testConfig);
 
     VideoConfig* testConfig2 = new VideoConfig(config1);
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManagerTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManagerTest.cpp
index 7f81b84..3a28e18 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManagerTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManagerTest.cpp
@@ -30,6 +30,8 @@
 using ::testing::Ref;
 using ::testing::Return;
 
+namespace
+{
 // RtpConfig
 const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE;
 const android::String8 kRemoteAddress("127.0.0.1");
@@ -68,7 +70,6 @@
 const int8_t kcodecModeRequest = 15;
 
 int32_t kSessionId = 0;
-
 static ImsMediaCondition gCondition;
 
 class AudioManagerCallback
@@ -686,4 +687,5 @@
     EXPECT_EQ(callback.resSessionId, kSessionId);
     EXPECT_EQ(callback.response, kAudioCallQualityChangedInd);
     EXPECT_EQ(callback.callQuality, quality);
-}
\ No newline at end of file
+}
+}  // namespace
\ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSessionTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSessionTest.cpp
index bd4a601..524e721 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSessionTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSessionTest.cpp
@@ -245,6 +245,14 @@
     EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1);
     EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1);
     EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1);
+
+    config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+
+    EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1);
 }
 
 TEST_F(AudioSessionTest, testStartAndHoldResumeWithDifferentRemoteAddress)
@@ -334,4 +342,84 @@
     EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1);
     EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1);
     EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1);
+}
+
+TEST_F(AudioSessionTest, testDeactivateActiveSession)
+{
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1);
+
+    EXPECT_EQ(session->deactivate(), true);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1);
+    EXPECT_EQ(session->getState(), kSessionStateSuspended);
+}
+
+TEST_F(AudioSessionTest, testDeactivateSendonlySession)
+{
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_SEND_ONLY);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateSending);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1);
+
+    EXPECT_EQ(session->deactivate(), true);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1);
+    EXPECT_EQ(session->getState(), kSessionStateSuspended);
+}
+
+TEST_F(AudioSessionTest, testDeactivateReceiveonlySession)
+{
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateReceiving);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1);
+
+    EXPECT_EQ(session->deactivate(), true);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1);
+    EXPECT_EQ(session->getState(), kSessionStateSuspended);
+}
+
+TEST_F(AudioSessionTest, testDeactivateAndResumeSession)
+{
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1);
+
+    EXPECT_EQ(session->deactivate(), true);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1);
+    EXPECT_EQ(session->getState(), kSessionStateSuspended);
+
+    config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateSuspended);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1);
+
+    config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpTx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtpRx), 1);
+    EXPECT_EQ(session->getGraphSize(kStreamRtcp), 1);
 }
\ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTxTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTxTest.cpp
index 18e2eff..156252e 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTxTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTxTest.cpp
@@ -219,7 +219,7 @@
     EXPECT_EQ(mockRtpEncoder->GetState(), kNodeStateRunning);
     EXPECT_EQ(graph->start(), RESULT_SUCCESS);
 
-    EXPECT_CALL(*mockRtpEncoder, OnDataFromFrontNode(MEDIASUBTYPE_DTMFSTART, _, 0, 0, 0, 0, _, _))
+    EXPECT_CALL(*mockRtpEncoder, OnDataFromFrontNode(MEDIASUBTYPE_DTMFSTART, _, 0, _, _, 0, _, _))
             .Times(1)
             .WillOnce(Return());
     EXPECT_CALL(*mockRtpEncoder,
@@ -230,7 +230,7 @@
             OnDataFromFrontNode(MEDIASUBTYPE_DTMF_PAYLOAD, NotNull(), 4, _, false, _, _, _))
             .Times(11)
             .WillRepeatedly(Return());
-    EXPECT_CALL(*mockRtpEncoder, OnDataFromFrontNode(MEDIASUBTYPE_DTMFEND, _, 0, 0, 0, 0, _, _))
+    EXPECT_CALL(*mockRtpEncoder, OnDataFromFrontNode(MEDIASUBTYPE_DTMFEND, _, 0, _, _, 0, _, _))
             .Times(1)
             .WillOnce(Return());
 
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/JitterNetworkAnalyserTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/JitterNetworkAnalyserTest.cpp
index 58edff7..e37aaa6 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/JitterNetworkAnalyserTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/JitterNetworkAnalyserTest.cpp
@@ -64,7 +64,8 @@
     for (int32_t i = 0; i < kNumFrames; i++)
     {
         timestamp += TEST_FRAME_INTERVAL;
-        arrivalTime += (TEST_FRAME_INTERVAL + kJitter);
+        int32_t jitter = i % 2 == 0 ? kJitter : -kJitter;
+        arrivalTime += (TEST_FRAME_INTERVAL + jitter);
 
         if (i == 0)
         {
@@ -72,7 +73,7 @@
         }
         else
         {
-            EXPECT_EQ(mAnalyzer->CalculateTransitTimeDifference(timestamp, arrivalTime), kJitter);
+            EXPECT_EQ(mAnalyzer->CalculateTransitTimeDifference(timestamp, arrivalTime), jitter);
         }
 
         currentJitterBufferSize =
@@ -128,7 +129,8 @@
     for (int32_t i = 0; i < kNumFrames; i++)
     {
         timestamp += TEST_FRAME_INTERVAL;
-        arrivalTime += (TEST_FRAME_INTERVAL + kJitter);
+        int32_t jitter = i % 2 == 0 ? kJitter : -kJitter;
+        arrivalTime += (TEST_FRAME_INTERVAL + jitter);
 
         if (i == 0)
         {
@@ -136,7 +138,7 @@
         }
         else
         {
-            EXPECT_EQ(mAnalyzer->CalculateTransitTimeDifference(timestamp, arrivalTime), kJitter);
+            EXPECT_EQ(mAnalyzer->CalculateTransitTimeDifference(timestamp, arrivalTime), jitter);
         }
 
         currentJitterBufferSize =
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNodeTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNodeTest.cpp
index 19c5104..cab0f38 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNodeTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNodeTest.cpp
@@ -310,7 +310,6 @@
 
     EXPECT_EQ(mFakeNode->GetFrameSize(), 0);
     mNode->OnDataFromFrontNode(MEDIASUBTYPE_UNDEFINED, testFrame, sizeof(testFrame), 0, false, 0);
-    mNode->ProcessData();
     EXPECT_EQ(mFakeNode->GetFrameSize(), sizeof(testFrame) + kRtpHeaderSize);
 }
 
@@ -338,14 +337,12 @@
 
     EXPECT_EQ(mFakeNode->GetFrameSize(), 0);
     mNode->OnDataFromFrontNode(MEDIASUBTYPE_RTPPAYLOAD, testFrame, sizeof(testFrame), 0, true, 0);
-    mNode->ProcessData();
 
     EXPECT_TRUE(mNode->SetCvoExtension(0, 0));
     EXPECT_EQ(mFakeNode->GetFrameSize(), sizeof(testFrame) + kRtpHeaderSize);
 
     mNode->OnDataFromFrontNode(
             MEDIASUBTYPE_VIDEO_IDR_FRAME, testFrame, sizeof(testFrame), 0, true, 0);
-    mNode->ProcessData();
     EXPECT_EQ(mFakeNode->GetFrameSize(), sizeof(testFrame) + kRtpHeaderSizeWithExtension);
 }
 
@@ -373,6 +370,5 @@
     EXPECT_EQ(mFakeNode->GetFrameSize(), 0);
     mNode->OnDataFromFrontNode(
             MEDIASUBTYPE_BITSTREAM_T140_RED, testFrame, sizeof(testFrame), 0, true, 0);
-    mNode->ProcessData();
     EXPECT_EQ(mFakeNode->GetFrameSize(), sizeof(testFrame) + kRtpHeaderSize);
 }
\ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/SocketNodeTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/SocketNodeTest.cpp
index 71432b0..cb39fb6 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/SocketNodeTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/SocketNodeTest.cpp
@@ -251,16 +251,22 @@
     EXPECT_EQ(mWriter->Start(), RESULT_SUCCESS);
 
     mReader->Stop();
+    EXPECT_EQ(mReader->GetState(), kNodeStateStopped);
 
     uint8_t testPacket[] = {0x80, 0x68, 0x00, 0x0b, 0xbc, 0xbc, 0xe8, 0xa4, 0x00, 0x04, 0x11, 0x68,
             0xf4, 0xfa, 0xfe, 0x67, 0x58, 0x84, 0x80};
 
+    ON_CALL(mMockNode, GetState).WillByDefault(Return(kNodeStateStopped));
+    EXPECT_CALL(mMockNode,
+            OnDataFromFrontNode(MEDIASUBTYPE_UNDEFINED, Pointee(Eq(*testPacket)),
+                    sizeof(testPacket), 0, false, 0, _, _))
+            .Times(0);
+
     mWriter->OnDataFromFrontNode(
             MEDIASUBTYPE_UNDEFINED, testPacket, sizeof(testPacket), 0, false, 0);
     mCondition.wait_timeout(20);
-    EXPECT_EQ(mReader->GetDataCount(), 1);
     EXPECT_EQ(mReader->Start(), RESULT_SUCCESS);
-    EXPECT_EQ(mReader->GetDataCount(), 0);
+    EXPECT_EQ(mReader->GetState(), kNodeStateRunning);
     mWriter->Stop();
     mReader->Stop();
 }
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManagerTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManagerTest.cpp
new file mode 100644
index 0000000..d9e6aae
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManagerTest.cpp
@@ -0,0 +1,390 @@
+/**
+ * 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 <gtest/gtest.h>
+#include <ImsMediaNetworkUtil.h>
+#include <TextConfig.h>
+#include <MockTextManager.h>
+#include <ImsMediaCondition.h>
+#include <unordered_map>
+#include <algorithm>
+
+using namespace android::telephony::imsmedia;
+
+using ::testing::Eq;
+using ::testing::Pointee;
+using ::testing::Return;
+
+namespace
+{
+// RtpConfig
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE;
+const android::String8 kRemoteAddress("127.0.0.1");
+const int32_t kRemotePort = 10000;
+const int8_t kDscp = 0;
+const int8_t kRxPayload = 100;
+const int8_t kTxPayload = 100;
+const int8_t kSamplingRate = 8;
+
+// RtcpConfig
+const android::String8 kCanonicalName("name");
+const int32_t kTransmitPort = 10001;
+const int32_t kIntervalSec = 3;
+const int32_t kRtcpXrBlockTypes = 0;
+
+// TextConfig
+const int32_t kCodecType = TextConfig::TEXT_T140_RED;
+const int32_t kBitrate = 100;
+const int8_t kRedundantPayload = 102;
+const int8_t kRedundantLevel = 3;
+const bool kKeepRedundantLevel = true;
+
+int32_t kSessionId = 0;
+static ImsMediaCondition gCondition;
+
+class TextManagerCallback
+{
+public:
+    int32_t resSessionId;
+    int32_t response;
+    TextConfig resConfig;
+    ImsMediaResult result;
+    int32_t inactivityType;
+    int32_t inactivityDuration;
+    android::String8 receivedRtt;
+
+    void resetRespond()
+    {
+        resSessionId = -1;
+        response = -1;
+        result = RESULT_NOT_READY;
+    }
+
+    void onCallback(const int id, const int event, const ImsMediaResult res)
+    {
+        resSessionId = id;
+        response = event;
+        result = res;
+    }
+
+    void onCallbackConfig(
+            const int id, const int event, const ImsMediaResult res, const TextConfig& config)
+    {
+        resSessionId = id;
+        response = event;
+        resConfig = config;
+        result = res;
+    }
+
+    void onCallbackInactivity(const int id, const int event, const int type, const int duration)
+    {
+        resSessionId = id;
+        response = event;
+        inactivityType = type;
+        inactivityDuration = duration;
+    }
+
+    void onCallbackRttReceived(const int id, const int event, const android::String16& text)
+    {
+        resSessionId = id;
+        response = event;
+        receivedRtt = android::String8(text);
+    }
+};
+
+static std::unordered_map<int, TextManagerCallback*> gMapCallback;
+
+class TextManagerTest : public ::testing::Test
+{
+public:
+    MockTextManager manager;
+    TextConfig config;
+    RtcpConfig rtcp;
+    int socketRtpFd;
+    int socketRtcpFd;
+    TextManagerCallback callback;
+
+    TextManagerTest()
+    {
+        socketRtpFd = -1;
+        socketRtcpFd = -1;
+        callback.resetRespond();
+        gCondition.reset();
+    }
+    ~TextManagerTest() {}
+
+protected:
+    virtual void SetUp() override
+    {
+        rtcp.setCanonicalName(kCanonicalName);
+        rtcp.setTransmitPort(kTransmitPort);
+        rtcp.setIntervalSec(kIntervalSec);
+        rtcp.setRtcpXrBlockTypes(kRtcpXrBlockTypes);
+
+        config.setMediaDirection(kMediaDirection);
+        config.setRemoteAddress(kRemoteAddress);
+        config.setRemotePort(kRemotePort);
+        config.setRtcpConfig(rtcp);
+        config.setDscp(kDscp);
+        config.setRxPayloadTypeNumber(kRxPayload);
+        config.setTxPayloadTypeNumber(kTxPayload);
+        config.setSamplingRateKHz(kSamplingRate);
+        config.setCodecType(kCodecType);
+        config.setBitrate(kBitrate);
+        config.setRedundantPayload(kRedundantPayload);
+        config.setRedundantLevel(kRedundantLevel);
+        config.setKeepRedundantLevel(kKeepRedundantLevel);
+
+        manager.setCallback(&textCallback);
+        gMapCallback.insert(std::make_pair(kSessionId, &callback));
+        const char testIp[] = "127.0.0.1";
+        unsigned int testPortRtp = 50000;
+        socketRtpFd = ImsMediaNetworkUtil::openSocket(testIp, testPortRtp, AF_INET);
+        EXPECT_NE(socketRtpFd, -1);
+        unsigned int testPortRtcp = 50001;
+        socketRtcpFd = ImsMediaNetworkUtil::openSocket(testIp, testPortRtcp, AF_INET);
+        EXPECT_NE(socketRtcpFd, -1);
+        gCondition.reset();
+    }
+
+    virtual void TearDown() override
+    {
+        if (socketRtpFd != -1)
+        {
+            ImsMediaNetworkUtil::closeSocket(socketRtpFd);
+        }
+
+        if (socketRtcpFd != -1)
+        {
+            ImsMediaNetworkUtil::closeSocket(socketRtcpFd);
+        }
+
+        gMapCallback.erase(kSessionId);
+    }
+
+    void openSession(const int32_t sessionId)
+    {
+        callback.resetRespond();
+        android::Parcel parcel;
+        parcel.writeInt32(kTextOpenSession);
+        parcel.writeInt32(socketRtpFd);
+        parcel.writeInt32(socketRtcpFd);
+        parcel.setDataPosition(0);
+        gCondition.reset();
+        manager.sendMessage(sessionId, parcel);
+        EXPECT_TRUE(!gCondition.wait_timeout(1000));
+        EXPECT_EQ(callback.resSessionId, sessionId);
+        EXPECT_EQ(callback.response, kTextOpenSessionSuccess);
+    }
+
+    void closeSession(const int32_t sessionId)
+    {
+        callback.resetRespond();
+        android::Parcel parcel;
+        parcel.writeInt32(kTextCloseSession);
+        parcel.setDataPosition(0);
+        gCondition.reset();
+        manager.sendMessage(sessionId, parcel);
+        EXPECT_TRUE(!gCondition.wait_timeout(1000));
+        EXPECT_EQ(callback.resSessionId, sessionId);
+        EXPECT_EQ(callback.response, kTextSessionClosed);
+    }
+
+    void testEventResponse(const int32_t sessionId, const int32_t event, TextConfig* config,
+            const int32_t response, const int32_t result)
+    {
+        callback.resetRespond();
+        android::Parcel parcel;
+        parcel.writeInt32(event);
+
+        if (config != nullptr)
+        {
+            config->writeToParcel(&parcel);
+        }
+
+        parcel.setDataPosition(0);
+        gCondition.reset();
+        manager.sendMessage(sessionId, parcel);
+        EXPECT_TRUE(!gCondition.wait_timeout(1000));
+        EXPECT_EQ(callback.resSessionId, sessionId);
+        EXPECT_EQ(callback.response, response);
+
+        if (callback.response >= kTextOpenSessionFailure &&
+                callback.response <= kTextModifySessionResponse)
+        {
+            EXPECT_EQ(result, result);
+
+            if (config != nullptr && callback.response == kTextModifySessionResponse)
+            {
+                EXPECT_EQ(callback.resConfig, *config);
+            }
+        }
+    }
+
+    static int32_t textCallback(int sessionId, const android::Parcel& parcel)
+    {
+        parcel.setDataPosition(0);
+
+        int response = parcel.readInt32();
+        ImsMediaResult result = RESULT_INVALID_PARAM;
+
+        auto callback = gMapCallback.find(sessionId);
+
+        if (callback != gMapCallback.end())
+        {
+            if (response >= kTextOpenSessionFailure && response <= kTextModifySessionResponse)
+            {
+                result = static_cast<ImsMediaResult>(parcel.readInt32());
+            }
+
+            switch (response)
+            {
+                case kTextModifySessionResponse:
+                {
+                    TextConfig resConfig;
+                    resConfig.readFromParcel(&parcel);
+                    (callback->second)->onCallbackConfig(sessionId, response, result, resConfig);
+                }
+                break;
+                case kTextMediaInactivityInd:
+                    (callback->second)
+                            ->onCallbackInactivity(
+                                    sessionId, response, parcel.readInt32(), parcel.readInt32());
+                    break;
+                case kTextRttReceived:
+                {
+                    android::String16 text;
+                    parcel.readString16(&text);
+                    (callback->second)->onCallbackRttReceived(sessionId, response, text);
+                }
+                break;
+                default:
+                    (callback->second)->onCallback(sessionId, response, result);
+                    break;
+            }
+        }
+
+        gCondition.signal();
+        return 0;
+    }
+};
+
+TEST_F(TextManagerTest, testOpenCloseSession)
+{
+    EXPECT_EQ(manager.getState(kSessionId), kSessionStateClosed);
+    openSession(kSessionId);
+    closeSession(kSessionId);
+}
+
+TEST_F(TextManagerTest, testModifySession)
+{
+    testEventResponse(kSessionId, kTextModifySession, nullptr, kTextModifySessionResponse,
+            RESULT_INVALID_PARAM);
+
+    openSession(kSessionId);
+
+    testEventResponse(kSessionId, kTextModifySession, nullptr, kTextModifySessionResponse,
+            RESULT_INVALID_PARAM);
+
+    testEventResponse(
+            kSessionId, kTextModifySession, &config, kTextModifySessionResponse, RESULT_SUCCESS);
+
+    closeSession(kSessionId);
+}
+
+TEST_F(TextManagerTest, testSendRtt)
+{
+    openSession(kSessionId);
+
+    const android::String8 text = android::String8("hello");
+    android::Parcel parcel;
+    parcel.writeInt32(kTextSendRtt);
+    android::String16 rttText(text);
+    parcel.writeString16(rttText);
+    parcel.setDataPosition(0);
+
+    EXPECT_CALL(manager, sendRtt(kSessionId, Pointee(Eq(text))))
+            .Times(1)
+            .WillOnce(Return(RESULT_NOT_READY));
+    manager.sendMessage(kSessionId, parcel);
+
+    closeSession(kSessionId);
+}
+
+TEST_F(TextManagerTest, testSetMediaQualityThreshold)
+{
+    openSession(kSessionId);
+
+    const std::vector<int32_t> kRtpInactivityTimerMillis = {10000, 20000};
+    const int32_t kRtcpInactivityTimerMillis = 20000;
+    const int32_t kRtpHysteresisTimeInMillis = 3000;
+    const int32_t kRtpPacketLossDurationMillis = 5000;
+    const std::vector<int32_t> kRtpPacketLossRate = {3, 5};
+    const std::vector<int32_t> kRtpJitterMillis = {100, 200};
+    const bool kNotifyCurrentStatus = false;
+
+    MediaQualityThreshold threshold;
+    threshold.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis);
+    threshold.setRtcpInactivityTimerMillis(kRtcpInactivityTimerMillis);
+    threshold.setRtpHysteresisTimeInMillis(kRtpHysteresisTimeInMillis);
+    threshold.setRtpPacketLossDurationMillis(kRtpPacketLossDurationMillis);
+    threshold.setRtpPacketLossRate(kRtpPacketLossRate);
+    threshold.setRtpJitterMillis(kRtpJitterMillis);
+    threshold.setNotifyCurrentStatus(kNotifyCurrentStatus);
+
+    android::Parcel parcel;
+    parcel.writeInt32(kTextSetMediaQualityThreshold);
+    threshold.writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+
+    EXPECT_CALL(manager, setMediaQualityThreshold(kSessionId, Pointee(Eq(threshold))))
+            .Times(1)
+            .WillOnce(Return());
+
+    manager.sendMessage(kSessionId, parcel);
+
+    closeSession(kSessionId);
+}
+
+TEST_F(TextManagerTest, testMediaInactivityInd)
+{
+    const int32_t kInactivityType = kProtocolRtp;
+    const int32_t kInactivityDuration = 10000;
+
+    ImsMediaEventHandler::SendEvent("TEXT_RESPONSE_EVENT", kTextMediaInactivityInd, kSessionId,
+            kInactivityType, kInactivityDuration);
+
+    gCondition.wait_timeout(20);
+    EXPECT_EQ(callback.resSessionId, kSessionId);
+    EXPECT_EQ(callback.response, kTextMediaInactivityInd);
+    EXPECT_EQ(callback.inactivityType, kInactivityType);
+    EXPECT_EQ(callback.inactivityDuration, kInactivityDuration);
+}
+
+TEST_F(TextManagerTest, testRttReceivedInd)
+{
+    const android::String8 testText = android::String8("hello");
+    android::String8* text = new android::String8(testText);
+
+    ImsMediaEventHandler::SendEvent("TEXT_RESPONSE_EVENT", kTextRttReceived, kSessionId,
+            reinterpret_cast<uint64_t>(text), 0);
+
+    gCondition.wait_timeout(20);
+    EXPECT_EQ(callback.resSessionId, kSessionId);
+    EXPECT_EQ(callback.response, kTextRttReceived);
+    EXPECT_EQ(callback.receivedRtt, testText);
+}
+}  // namespace
\ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextSessionTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextSessionTest.cpp
new file mode 100644
index 0000000..93cded7
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextSessionTest.cpp
@@ -0,0 +1,242 @@
+/**
+ * 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 <gtest/gtest.h>
+#include <ImsMediaNetworkUtil.h>
+#include <ImsMediaCondition.h>
+#include <TextConfig.h>
+#include <TextSession.h>
+
+using namespace android::telephony::imsmedia;
+
+// RtpConfig
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE;
+const android::String8 kRemoteAddress("127.0.0.1");
+const int32_t kRemotePort = 10000;
+const int8_t kDscp = 0;
+const int8_t kRxPayload = 96;
+const int8_t kTxPayload = 96;
+const int8_t kSamplingRate = 16;
+
+// RtcpConfig
+const android::String8 kCanonicalName("name");
+const int32_t kTransmitPort = 1001;
+const int32_t kIntervalSec = 5;
+const int32_t kRtcpXrBlockTypes = RtcpConfig::FLAG_RTCPXR_STATISTICS_SUMMARY_REPORT_BLOCK |
+        RtcpConfig::FLAG_RTCPXR_VOIP_METRICS_REPORT_BLOCK;
+
+// TextConfig
+const int32_t kCodecType = TextConfig::TEXT_T140_RED;
+const int32_t kBitrate = 100;
+const int8_t kRedundantPayload = 102;
+const int8_t kRedundantLevel = 2;
+const bool kKeepRedundantLevel = true;
+
+class TextSessionTest : public ::testing::Test
+{
+public:
+    TextSessionTest()
+    {
+        session = nullptr;
+        socketRtpFd = -1;
+        socketRtcpFd = -1;
+    }
+    virtual ~TextSessionTest() {}
+
+protected:
+    TextSession* session;
+    TextConfig config;
+    RtcpConfig rtcp;
+    int socketRtpFd;
+    int socketRtcpFd;
+
+    virtual void SetUp() override
+    {
+        rtcp.setCanonicalName(kCanonicalName);
+        rtcp.setTransmitPort(kTransmitPort);
+        rtcp.setIntervalSec(kIntervalSec);
+        rtcp.setRtcpXrBlockTypes(kRtcpXrBlockTypes);
+
+        config.setMediaDirection(kMediaDirection);
+        config.setRemoteAddress(kRemoteAddress);
+        config.setRemotePort(kRemotePort);
+        config.setRtcpConfig(rtcp);
+        config.setDscp(kDscp);
+        config.setRxPayloadTypeNumber(kRxPayload);
+        config.setTxPayloadTypeNumber(kTxPayload);
+        config.setSamplingRateKHz(kSamplingRate);
+        config.setCodecType(kCodecType);
+        config.setBitrate(kBitrate);
+        config.setRedundantPayload(kRedundantPayload);
+        config.setRedundantLevel(kRedundantLevel);
+        config.setKeepRedundantLevel(kKeepRedundantLevel);
+
+        session = new TextSession();
+        const char testIp[] = "127.0.0.1";
+        unsigned int testPortRtp = 30000;
+        socketRtpFd = ImsMediaNetworkUtil::openSocket(testIp, testPortRtp, AF_INET);
+        EXPECT_NE(socketRtpFd, -1);
+        unsigned int testPortRtcp = 30001;
+        socketRtcpFd = ImsMediaNetworkUtil::openSocket(testIp, testPortRtcp, AF_INET);
+        EXPECT_NE(socketRtcpFd, -1);
+    }
+
+    virtual void TearDown() override
+    {
+        if (session != nullptr)
+        {
+            delete session;
+        }
+
+        if (socketRtpFd != -1)
+        {
+            ImsMediaNetworkUtil::closeSocket(socketRtpFd);
+        }
+
+        if (socketRtcpFd != -1)
+        {
+            ImsMediaNetworkUtil::closeSocket(socketRtcpFd);
+        }
+    }
+};
+
+TEST_F(TextSessionTest, testLocalEndpoint)
+{
+    EXPECT_EQ(session->getState(), kSessionStateOpened);
+    EXPECT_EQ(session->getLocalRtpFd(), -1);
+    EXPECT_EQ(session->getLocalRtcpFd(), -1);
+
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    EXPECT_EQ(session->getLocalRtpFd(), socketRtpFd);
+    EXPECT_EQ(session->getLocalRtcpFd(), socketRtcpFd);
+}
+
+TEST_F(TextSessionTest, testStartGraphFail)
+{
+    EXPECT_EQ(session->startGraph(nullptr), RESULT_INVALID_PARAM);
+    EXPECT_EQ(session->getState(), kSessionStateOpened);
+
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    config.setRemoteAddress(android::String8(""));
+    EXPECT_EQ(session->startGraph(&config), RESULT_INVALID_PARAM);
+    EXPECT_EQ(session->getState(), kSessionStateOpened);
+}
+
+TEST_F(TextSessionTest, testStartGraphAndUpdate)
+{
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+
+    // normal update
+    config.setTxPayloadTypeNumber(120);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+
+    // create one more graph
+    config.setRemotePort(20000);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+}
+
+TEST_F(TextSessionTest, testStartGraphSendOnly)
+{
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_SEND_ONLY);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+}
+
+TEST_F(TextSessionTest, testStartGraphReceiveOnly)
+{
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+}
+
+TEST_F(TextSessionTest, testStartGraphInactive)
+{
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateSuspended);
+}
+
+TEST_F(TextSessionTest, testStartAndHoldResume)
+{
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+
+    config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateSuspended);
+
+    config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+}
+
+TEST_F(TextSessionTest, testDeactivateActiveSession)
+{
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+
+    EXPECT_EQ(session->deactivate(), true);
+    EXPECT_EQ(session->getState(), kSessionStateSuspended);
+}
+
+TEST_F(TextSessionTest, testDeactivateSendonlySession)
+{
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_SEND_ONLY);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+
+    EXPECT_EQ(session->deactivate(), true);
+    EXPECT_EQ(session->getState(), kSessionStateSuspended);
+}
+
+TEST_F(TextSessionTest, testDeactivateReceiveonlySession)
+{
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+
+    EXPECT_EQ(session->deactivate(), true);
+    EXPECT_EQ(session->getState(), kSessionStateSuspended);
+}
+
+TEST_F(TextSessionTest, testDeactivateAndResumeSession)
+{
+    session->setLocalEndPoint(socketRtpFd, socketRtcpFd);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+
+    EXPECT_EQ(session->deactivate(), true);
+    EXPECT_EQ(session->getState(), kSessionStateSuspended);
+
+    config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateSuspended);
+
+    config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE);
+    EXPECT_EQ(session->startGraph(&config), RESULT_SUCCESS);
+    EXPECT_EQ(session->getState(), kSessionStateActive);
+}
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManagerTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManagerTest.cpp
new file mode 100644
index 0000000..63b8943
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManagerTest.cpp
@@ -0,0 +1,465 @@
+/**
+ * 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 <gtest/gtest.h>
+#include <ImsMediaNetworkUtil.h>
+#include <media/NdkImageReader.h>
+#include <VideoConfig.h>
+#include <MockVideoManager.h>
+#include <ImsMediaCondition.h>
+#include <unordered_map>
+#include <algorithm>
+
+using namespace android::telephony::imsmedia;
+
+using ::testing::Eq;
+using ::testing::Pointee;
+using ::testing::Return;
+
+namespace
+{
+// RtpConfig
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_NO_FLOW;
+const android::String8 kRemoteAddress("0.0.0.0");
+const int32_t kRemotePort = 1000;
+const int32_t kMtu = 1500;
+const int8_t kDscp = 0;
+const int8_t kRxPayload = 102;
+const int8_t kTxPayload = 102;
+const int8_t kSamplingRate = 90;
+
+// RtcpConfig
+const android::String8 kCanonicalName("name");
+const int32_t kTransmitPort = 1001;
+const int32_t kIntervalSec = 1500;
+const int32_t kRtcpXrBlockTypes = RtcpConfig::FLAG_RTCPXR_STATISTICS_SUMMARY_REPORT_BLOCK |
+        RtcpConfig::FLAG_RTCPXR_VOIP_METRICS_REPORT_BLOCK;
+
+// VideoConfig
+const int32_t kVideoMode = VideoConfig::VIDEO_MODE_PREVIEW;
+const int32_t kCodecType = VideoConfig::CODEC_AVC;
+const int32_t kFramerate = DEFAULT_FRAMERATE;
+const int32_t kBitrate = DEFAULT_BITRATE;
+const int32_t kCodecProfile = VideoConfig::AVC_PROFILE_BASELINE;
+const int32_t kCodecLevel = VideoConfig::AVC_LEVEL_12;
+const int32_t kIntraFrameIntervalSec = 1;
+const int32_t kPacketizationMode = VideoConfig::MODE_NON_INTERLEAVED;
+const int32_t kCameraId = 0;
+const int32_t kCameraZoom = 10;
+const int32_t kResolutionWidth = DEFAULT_RESOLUTION_WIDTH;
+const int32_t kResolutionHeight = DEFAULT_RESOLUTION_HEIGHT;
+const android::String8 kPauseImagePath("data/user_de/0/com.android.telephony.imsmedia/test.jpg");
+const int32_t kDeviceOrientationDegree = 0;
+const int32_t kCvoValue = 1;
+const int32_t kRtcpFbTypes = VideoConfig::RTP_FB_NONE;
+
+int32_t kSessionId = 0;
+static ImsMediaCondition gCondition;
+
+class VideoManagerCallback
+{
+public:
+    int32_t resSessionId;
+    int32_t response;
+    VideoConfig resConfig;
+    ImsMediaResult result;
+    int32_t inactivityType;
+    int32_t inactivityDuration;
+    int32_t peerResolutionWidth;
+    int32_t peerResolutionHeight;
+
+    void resetRespond()
+    {
+        resSessionId = -1;
+        response = -1;
+        result = RESULT_NOT_READY;
+    }
+
+    void onCallback(const int id, const int event, const ImsMediaResult res)
+    {
+        resSessionId = id;
+        response = event;
+        result = res;
+    }
+
+    void onCallbackConfig(
+            const int id, const int event, const ImsMediaResult res, const VideoConfig& config)
+    {
+        resSessionId = id;
+        response = event;
+        resConfig = config;
+        result = res;
+    }
+
+    void onCallbackInactivity(const int id, const int event, const int type, const int duration)
+    {
+        resSessionId = id;
+        response = event;
+        inactivityType = type;
+        inactivityDuration = duration;
+    }
+
+    void onCallbackPeerDimensionChanged(
+            const int id, const int event, const int width, const int height)
+    {
+        resSessionId = id;
+        response = event;
+        peerResolutionWidth = width;
+        peerResolutionHeight = height;
+    }
+};
+
+static std::unordered_map<int, VideoManagerCallback*> gMapCallback;
+
+class VideoManagerTest : public ::testing::Test
+{
+public:
+    MockVideoManager manager;
+    VideoConfig config;
+    RtcpConfig rtcp;
+    int socketRtpFd;
+    int socketRtcpFd;
+    VideoManagerCallback callback;
+
+    VideoManagerTest()
+    {
+        socketRtpFd = -1;
+        socketRtcpFd = -1;
+        callback.resetRespond();
+        gCondition.reset();
+    }
+    ~VideoManagerTest() {}
+
+protected:
+    virtual void SetUp() override
+    {
+        rtcp.setCanonicalName(kCanonicalName);
+        rtcp.setTransmitPort(kTransmitPort);
+        rtcp.setIntervalSec(kIntervalSec);
+        rtcp.setRtcpXrBlockTypes(kRtcpXrBlockTypes);
+        config.setMediaDirection(kMediaDirection);
+        config.setRemoteAddress(kRemoteAddress);
+        config.setRemotePort(kRemotePort);
+        config.setRtcpConfig(rtcp);
+        config.setMaxMtuBytes(kMtu);
+        config.setDscp(kDscp);
+        config.setRxPayloadTypeNumber(kRxPayload);
+        config.setTxPayloadTypeNumber(kTxPayload);
+        config.setSamplingRateKHz(kSamplingRate);
+        config.setVideoMode(kVideoMode);
+        config.setCodecType(kCodecType);
+        config.setFramerate(kFramerate);
+        config.setBitrate(kBitrate);
+        config.setCodecProfile(kCodecProfile);
+        config.setCodecLevel(kCodecLevel);
+        config.setIntraFrameInterval(kIntraFrameIntervalSec);
+        config.setPacketizationMode(kPacketizationMode);
+        config.setCameraId(kCameraId);
+        config.setCameraZoom(kCameraZoom);
+        config.setResolutionWidth(kResolutionWidth);
+        config.setResolutionHeight(kResolutionHeight);
+        config.setPauseImagePath(kPauseImagePath);
+        config.setDeviceOrientationDegree(kDeviceOrientationDegree);
+        config.setCvoValue(kCvoValue);
+        config.setRtcpFbType(kRtcpFbTypes);
+
+        manager.setCallback(&VideoCallback);
+        gMapCallback.insert(std::make_pair(kSessionId, &callback));
+        const char testIp[] = "127.0.0.1";
+        unsigned int testPortRtp = 50000;
+        socketRtpFd = ImsMediaNetworkUtil::openSocket(testIp, testPortRtp, AF_INET);
+        EXPECT_NE(socketRtpFd, -1);
+        unsigned int testPortRtcp = 50001;
+        socketRtcpFd = ImsMediaNetworkUtil::openSocket(testIp, testPortRtcp, AF_INET);
+        EXPECT_NE(socketRtcpFd, -1);
+        gCondition.reset();
+    }
+
+    virtual void TearDown() override
+    {
+        if (socketRtpFd != -1)
+        {
+            ImsMediaNetworkUtil::closeSocket(socketRtpFd);
+        }
+
+        if (socketRtcpFd != -1)
+        {
+            ImsMediaNetworkUtil::closeSocket(socketRtcpFd);
+        }
+
+        gMapCallback.erase(kSessionId);
+    }
+
+    void openSession(const int32_t sessionId)
+    {
+        callback.resetRespond();
+        android::Parcel parcel;
+        parcel.writeInt32(kVideoOpenSession);
+        parcel.writeInt32(socketRtpFd);
+        parcel.writeInt32(socketRtcpFd);
+        parcel.setDataPosition(0);
+        gCondition.reset();
+        manager.sendMessage(sessionId, parcel);
+        EXPECT_TRUE(!gCondition.wait_timeout(1000));
+        EXPECT_EQ(callback.resSessionId, sessionId);
+        EXPECT_EQ(callback.response, kVideoOpenSessionSuccess);
+    }
+
+    void closeSession(const int32_t sessionId)
+    {
+        callback.resetRespond();
+        android::Parcel parcel;
+        parcel.writeInt32(kVideoCloseSession);
+        parcel.setDataPosition(0);
+        gCondition.reset();
+        manager.sendMessage(sessionId, parcel);
+        EXPECT_TRUE(!gCondition.wait_timeout(1000));
+        EXPECT_EQ(callback.resSessionId, sessionId);
+        EXPECT_EQ(callback.response, kVideoSessionClosed);
+    }
+
+    void testEventResponse(const int32_t sessionId, const int32_t event, VideoConfig* config,
+            const int32_t response, const int32_t result)
+    {
+        callback.resetRespond();
+        android::Parcel parcel;
+        parcel.writeInt32(event);
+
+        if (config != nullptr)
+        {
+            config->writeToParcel(&parcel);
+        }
+
+        parcel.setDataPosition(0);
+        gCondition.reset();
+        manager.sendMessage(sessionId, parcel);
+        EXPECT_TRUE(!gCondition.wait_timeout(1000));
+        EXPECT_EQ(callback.resSessionId, sessionId);
+        EXPECT_EQ(callback.response, response);
+
+        if (callback.response >= kVideoOpenSessionFailure &&
+                callback.response <= kVideoModifySessionResponse)
+        {
+            EXPECT_EQ(result, result);
+
+            if (config != nullptr && callback.response == kVideoModifySessionResponse)
+            {
+                EXPECT_EQ(callback.resConfig, *config);
+            }
+        }
+    }
+
+    static int32_t VideoCallback(int sessionId, const android::Parcel& parcel)
+    {
+        parcel.setDataPosition(0);
+
+        int response = parcel.readInt32();
+        ImsMediaResult result = RESULT_INVALID_PARAM;
+
+        auto callback = gMapCallback.find(sessionId);
+
+        if (callback != gMapCallback.end())
+        {
+            if (response >= kVideoOpenSessionFailure && response <= kVideoModifySessionResponse)
+            {
+                result = static_cast<ImsMediaResult>(parcel.readInt32());
+            }
+
+            switch (response)
+            {
+                case kVideoModifySessionResponse:
+                {
+                    VideoConfig resConfig;
+                    resConfig.readFromParcel(&parcel);
+                    (callback->second)->onCallbackConfig(sessionId, response, result, resConfig);
+                }
+                break;
+                case kVideoPeerDimensionChanged:
+                    (callback->second)
+                            ->onCallbackPeerDimensionChanged(
+                                    sessionId, response, parcel.readInt32(), parcel.readInt32());
+                    break;
+                case kVideoMediaInactivityInd:
+                    (callback->second)
+                            ->onCallbackInactivity(
+                                    sessionId, response, parcel.readInt32(), parcel.readInt32());
+                    break;
+                case kVideoFirstMediaPacketInd:
+                default:
+                    (callback->second)->onCallback(sessionId, response, result);
+                    break;
+            }
+        }
+
+        gCondition.signal();
+        return 0;
+    }
+};
+
+TEST_F(VideoManagerTest, testOpenCloseSession)
+{
+    EXPECT_EQ(manager.getState(kSessionId), kSessionStateClosed);
+    openSession(kSessionId);
+    closeSession(kSessionId);
+}
+
+TEST_F(VideoManagerTest, testModifySession)
+{
+    testEventResponse(kSessionId, kVideoModifySession, nullptr, kVideoModifySessionResponse,
+            RESULT_INVALID_PARAM);
+
+    openSession(kSessionId);
+
+    testEventResponse(kSessionId, kVideoModifySession, nullptr, kVideoModifySessionResponse,
+            RESULT_INVALID_PARAM);
+
+    testEventResponse(
+            kSessionId, kVideoModifySession, &config, kVideoModifySessionResponse, RESULT_SUCCESS);
+
+    closeSession(kSessionId);
+}
+
+TEST_F(VideoManagerTest, testSetPreviewSurface)
+{
+    openSession(kSessionId);
+
+    AImageReader* previewReader;
+    AImageReader_new(
+            kResolutionWidth, kResolutionHeight, AIMAGE_FORMAT_YUV_420_888, 1, &previewReader);
+
+    ANativeWindow* previewSurface;
+    AImageReader_getWindow(previewReader, &previewSurface);
+
+    EXPECT_CALL(manager, setPreviewSurfaceToSession(kSessionId, Eq(previewSurface)))
+            .Times(1)
+            .WillOnce(Return(RESULT_SUCCESS));
+
+    manager.setPreviewSurface(kSessionId, previewSurface);
+
+    gCondition.wait_timeout(20);
+    closeSession(kSessionId);
+}
+
+TEST_F(VideoManagerTest, testSetDisplaySurface)
+{
+    openSession(kSessionId);
+
+    AImageReader* displayReader;
+    AImageReader_new(
+            kResolutionWidth, kResolutionHeight, AIMAGE_FORMAT_YUV_420_888, 1, &displayReader);
+
+    ANativeWindow* displaySurface;
+    AImageReader_getWindow(displayReader, &displaySurface);
+
+    EXPECT_CALL(manager, setDisplaySurfaceToSession(kSessionId, Eq(displaySurface)))
+            .Times(1)
+            .WillOnce(Return(RESULT_SUCCESS));
+
+    manager.setDisplaySurface(kSessionId, displaySurface);
+
+    gCondition.wait_timeout(20);
+    closeSession(kSessionId);
+}
+
+TEST_F(VideoManagerTest, testSetMediaQualityThreshold)
+{
+    openSession(kSessionId);
+
+    const std::vector<int32_t> kRtpInactivityTimerMillis = {10000, 20000};
+    const int32_t kRtcpInactivityTimerMillis = 20000;
+    const int32_t kRtpHysteresisTimeInMillis = 3000;
+    const int32_t kRtpPacketLossDurationMillis = 5000;
+    const std::vector<int32_t> kRtpPacketLossRate = {3, 5};
+    const std::vector<int32_t> kRtpJitterMillis = {100, 200};
+    const bool kNotifyCurrentStatus = false;
+
+    MediaQualityThreshold threshold;
+    threshold.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis);
+    threshold.setRtcpInactivityTimerMillis(kRtcpInactivityTimerMillis);
+    threshold.setRtpHysteresisTimeInMillis(kRtpHysteresisTimeInMillis);
+    threshold.setRtpPacketLossDurationMillis(kRtpPacketLossDurationMillis);
+    threshold.setRtpPacketLossRate(kRtpPacketLossRate);
+    threshold.setRtpJitterMillis(kRtpJitterMillis);
+    threshold.setNotifyCurrentStatus(kNotifyCurrentStatus);
+
+    android::Parcel parcel;
+    parcel.writeInt32(kVideoSetMediaQualityThreshold);
+    threshold.writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+
+    EXPECT_CALL(manager, setMediaQualityThreshold(kSessionId, Pointee(Eq(threshold))))
+            .Times(1)
+            .WillOnce(Return());
+
+    manager.sendMessage(kSessionId, parcel);
+
+    closeSession(kSessionId);
+}
+
+TEST_F(VideoManagerTest, testFirstMediaPacketInd)
+{
+    ImsMediaEventHandler::SendEvent(
+            "VIDEO_RESPONSE_EVENT", kVideoFirstMediaPacketInd, kSessionId, 0, 0);
+
+    gCondition.wait_timeout(20);
+    EXPECT_EQ(callback.resSessionId, kSessionId);
+    EXPECT_EQ(callback.response, kVideoFirstMediaPacketInd);
+}
+
+TEST_F(VideoManagerTest, testPeerDimensionChangedInd)
+{
+    ImsMediaEventHandler::SendEvent("VIDEO_RESPONSE_EVENT", kVideoPeerDimensionChanged, kSessionId,
+            kResolutionWidth, kResolutionHeight);
+
+    gCondition.wait_timeout(20);
+    EXPECT_EQ(callback.resSessionId, kSessionId);
+    EXPECT_EQ(callback.response, kVideoPeerDimensionChanged);
+    EXPECT_EQ(callback.peerResolutionWidth, kResolutionWidth);
+    EXPECT_EQ(callback.peerResolutionHeight, kResolutionHeight);
+}
+
+TEST_F(VideoManagerTest, testMediaInactivityInd)
+{
+    const int32_t kInactivityType = kProtocolRtp;
+
+    ImsMediaEventHandler::SendEvent(
+            "VIDEO_RESPONSE_EVENT", kVideoMediaInactivityInd, kSessionId, kInactivityType, 0);
+
+    gCondition.wait_timeout(20);
+    EXPECT_EQ(callback.resSessionId, kSessionId);
+    EXPECT_EQ(callback.response, kVideoMediaInactivityInd);
+    EXPECT_EQ(callback.inactivityType, kInactivityType);
+}
+
+TEST_F(VideoManagerTest, testInternalEvent)
+{
+    const uint64_t kParamA = 1;
+    const uint64_t kParamB = 2;
+
+    for (int32_t request = kRequestVideoCvoUpdate; request <= kRequestRoundTripTimeDelayUpdate;
+            request++)
+    {
+        EXPECT_CALL(manager, SendInternalEvent(request, kSessionId, Eq(kParamA), Eq(kParamB)))
+                .Times(1)
+                .WillOnce(Return());
+
+        ImsMediaEventHandler::SendEvent(
+                "VIDEO_REQUEST_EVENT", request, kSessionId, kParamA, kParamB);
+        gCondition.wait_timeout(20);
+    }
+}
+
+}  // namespace
\ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/text/MockTextManager.h b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/text/MockTextManager.h
new file mode 100644
index 0000000..c7bbe92
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/text/MockTextManager.h
@@ -0,0 +1,34 @@
+/**
+ * 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 MOCK_TEXT_MANAGER_H
+#define MOCK_TEXT_MANAGER_H
+
+#include <TextManager.h>
+#include <ImsMediaDefine.h>
+#include <gmock/gmock.h>
+
+class MockTextManager : public TextManager
+{
+public:
+    MockTextManager() { sManager = this; }
+    virtual ~MockTextManager() { sManager = nullptr; }
+    MOCK_METHOD(ImsMediaResult, sendRtt, (int sessionId, const android::String8* text), (override));
+    MOCK_METHOD(void, setMediaQualityThreshold, (int sessionId, MediaQualityThreshold* threshold),
+            (override));
+};
+
+#endif
\ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/video/MockVideoManager.h b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/video/MockVideoManager.h
new file mode 100644
index 0000000..ff31cbd
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/video/MockVideoManager.h
@@ -0,0 +1,39 @@
+/**
+ * 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 MOCK_VIDEO_MANAGER_H
+#define MOCK_VIDEO_MANAGER_H
+
+#include <VideoManager.h>
+#include <ImsMediaDefine.h>
+#include <gmock/gmock.h>
+
+class MockVideoManager : public VideoManager
+{
+public:
+    MockVideoManager() { sManager = this; }
+    virtual ~MockVideoManager() { sManager = nullptr; }
+    MOCK_METHOD(ImsMediaResult, setPreviewSurfaceToSession,
+            (const int sessionId, ANativeWindow* surface), (override));
+    MOCK_METHOD(ImsMediaResult, setDisplaySurfaceToSession,
+            (const int sessionId, ANativeWindow* surface), (override));
+    MOCK_METHOD(void, setMediaQualityThreshold,
+            (const int sessionId, MediaQualityThreshold* threshold), (override));
+    MOCK_METHOD(void, SendInternalEvent,
+            (uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB), (override));
+};
+
+#endif
\ No newline at end of file