Merge "Disconnect external cameras if sensor privacy enabled" into sc-dev
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 1cde4c6..52cd4b4 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -8908,13 +8908,27 @@
      * camera's crop region is set to maximum size, the FOV of the physical streams for the
      * ultrawide lens will be the same as the logical stream, by making the crop region
      * smaller than its active array size to compensate for the smaller focal length.</p>
-     * <p>Even if the underlying physical cameras have different RAW characteristics (such as
-     * size or CFA pattern), a logical camera can still advertise RAW capability. In this
-     * case, when the application configures a RAW stream, the camera device will make sure
-     * the active physical camera will remain active to ensure consistent RAW output
-     * behavior, and not switch to other physical cameras.</p>
+     * <p>There are two ways for the application to capture RAW images from a logical camera
+     * with RAW capability:</p>
+     * <ul>
+     * <li>Because the underlying physical cameras may have different RAW capabilities (such
+     * as resolution or CFA pattern), to maintain backward compatibility, when a RAW stream
+     * is configured, the camera device makes sure the default active physical camera remains
+     * active and does not switch to other physical cameras. (One exception is that, if the
+     * logical camera consists of identical image sensors and advertises multiple focalLength
+     * due to different lenses, the camera device may generate RAW images from different
+     * physical cameras based on the focalLength being set by the application.) This
+     * backward-compatible approach usually results in loss of optical zoom, to telephoto
+     * lens or to ultrawide lens.</li>
+     * <li>Alternatively, to take advantage of the full zoomRatio range of the logical camera,
+     * the application should use <a href="https://developer.android.com/reference/android/hardware/camera2/MultiResolutionImageReader.html">MultiResolutionImageReader</a>
+     * to capture RAW images from the currently active physical camera. Because different
+     * physical camera may have different RAW characteristics, the application needs to use
+     * the characteristics and result metadata of the active physical camera for the
+     * relevant RAW metadata.</li>
+     * </ul>
      * <p>The capture request and result metadata tags required for backward compatible camera
-     * functionalities will be solely based on the logical camera capabiltity. On the other
+     * functionalities will be solely based on the logical camera capability. On the other
      * hand, the use of manual capture controls (sensor or post-processing) with a
      * logical camera may result in unexpected behavior when the HAL decides to switch
      * between physical cameras with different characteristics under the hood. For example,
diff --git a/drm/drmserver/drmserver.rc b/drm/drmserver/drmserver.rc
index de46fb9..eb176c1 100644
--- a/drm/drmserver/drmserver.rc
+++ b/drm/drmserver/drmserver.rc
@@ -1,5 +1,12 @@
 service drm /system/bin/drmserver
+    disabled
     class main
     user drm
     group drm system inet drmrpc readproc
     writepid /dev/cpuset/foreground/tasks
+
+on property:drm.service.enabled=true
+    start drm
+
+on property:drm.service.enabled=1
+    start drm
diff --git a/drm/libdrmframework/DrmManagerClientImpl.cpp b/drm/libdrmframework/DrmManagerClientImpl.cpp
index b0a441b..a2cac3f 100644
--- a/drm/libdrmframework/DrmManagerClientImpl.cpp
+++ b/drm/libdrmframework/DrmManagerClientImpl.cpp
@@ -52,25 +52,13 @@
 const sp<IDrmManagerService>& DrmManagerClientImpl::getDrmManagerService() {
     Mutex::Autolock lock(sMutex);
     if (NULL == sDrmManagerService.get()) {
-        char value[PROPERTY_VALUE_MAX];
-        if (property_get("drm.service.enabled", value, NULL) == 0) {
-            // Drm is undefined for this device
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder = sm->getService(String16("drm.drmManager"));
+        if (binder == NULL) {
+            // Do NOT retry; IServiceManager already waits for ~5 seconds
+            // in getService if a service doesn't yet exist.
             return sDrmManagerService;
         }
-
-        sp<IServiceManager> sm = defaultServiceManager();
-        sp<IBinder> binder;
-        do {
-            binder = sm->getService(String16("drm.drmManager"));
-            if (binder != 0) {
-                break;
-            }
-            ALOGW("DrmManagerService not published, waiting...");
-            struct timespec reqt;
-            reqt.tv_sec  = 0;
-            reqt.tv_nsec = 500000000; //0.5 sec
-            nanosleep(&reqt, NULL);
-        } while (true);
         if (NULL == sDeathNotifier.get()) {
             sDeathNotifier = new DeathNotifier();
         }
diff --git a/media/codec2/components/mp3/C2SoftMp3Dec.cpp b/media/codec2/components/mp3/C2SoftMp3Dec.cpp
index 7137767..30d7394 100644
--- a/media/codec2/components/mp3/C2SoftMp3Dec.cpp
+++ b/media/codec2/components/mp3/C2SoftMp3Dec.cpp
@@ -16,6 +16,7 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "C2SoftMp3Dec"
+#include <inttypes.h>
 #include <log/log.h>
 
 #include <numeric>
@@ -485,10 +486,10 @@
         }
     }
 
-    uint64_t outTimeStamp = mProcessedSamples * 1000000ll / samplingRate;
+    int64_t outTimeStamp = mProcessedSamples * 1000000ll / samplingRate;
     mProcessedSamples += ((outSize - outOffset) / (numChannels * sizeof(int16_t)));
-    ALOGV("out buffer attr. offset %d size %d timestamp %u", outOffset, outSize - outOffset,
-          (uint32_t)(mAnchorTimeStamp + outTimeStamp));
+    ALOGV("out buffer attr. offset %d size %d timestamp %" PRId64 " ", outOffset,
+          outSize - outOffset, mAnchorTimeStamp + outTimeStamp);
     decodedSizes.clear();
     work->worklets.front()->output.flags = work->input.flags;
     work->worklets.front()->output.buffers.clear();
diff --git a/media/codec2/components/mp3/C2SoftMp3Dec.h b/media/codec2/components/mp3/C2SoftMp3Dec.h
index 402bdc4..e2dfcf3 100644
--- a/media/codec2/components/mp3/C2SoftMp3Dec.h
+++ b/media/codec2/components/mp3/C2SoftMp3Dec.h
@@ -63,7 +63,7 @@
     bool mSignalledError;
     bool mSignalledOutputEos;
     bool mGaplessBytes;
-    uint64_t mAnchorTimeStamp;
+    int64_t mAnchorTimeStamp;
     uint64_t mProcessedSamples;
 
     status_t initDecoder();
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index abd8b2d..74b099c 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -46,8 +46,8 @@
         {"mp4a-latm", "bbb_aac_stereo_128kbps_48000hz.aac", "bbb_aac_stereo_128kbps_48000hz.info"},
         {"mp4a-latm", "bbb_aac_stereo_128kbps_48000hz.aac",
          "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"},
-        {"audio/mpeg", "bbb_mp3_stereo_192kbps_48000hz.mp3", "bbb_mp3_stereo_192kbps_48000hz.info"},
-        {"audio/mpeg", "bbb_mp3_stereo_192kbps_48000hz.mp3",
+        {"mpeg", "bbb_mp3_stereo_192kbps_48000hz.mp3", "bbb_mp3_stereo_192kbps_48000hz.info"},
+        {"mpeg", "bbb_mp3_stereo_192kbps_48000hz.mp3",
          "bbb_mp3_stereo_192kbps_48000hz_multi_frame.info"},
         {"3gpp", "sine_amrnb_1ch_12kbps_8000hz.amrnb", "sine_amrnb_1ch_12kbps_8000hz.info"},
         {"3gpp", "sine_amrnb_1ch_12kbps_8000hz.amrnb",
@@ -303,7 +303,7 @@
     int streamCount = 0;
 
     for (size_t i = 0; i < gCompToFiles.size(); ++i) {
-        if (mMime.find(gCompToFiles[i].mime) != std::string::npos) {
+        if (!mMime.compare("audio/" + gCompToFiles[i].mime)) {
             if (streamCount == streamIndex) {
                 mInputFile = sResourceDir + gCompToFiles[i].inputFile;
                 mInfoFile = sResourceDir + gCompToFiles[i].infoFile;
diff --git a/media/codec2/hidl/1.0/vts/functional/video/Android.bp b/media/codec2/hidl/1.0/vts/functional/video/Android.bp
index f211ecf..ecc4f9d 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/Android.bp
+++ b/media/codec2/hidl/1.0/vts/functional/video/Android.bp
@@ -36,6 +36,8 @@
         "libgui",
         "libutils",
         "libcrypto",
+        "libdatasource",
+        "libui",
     ],
     data: [":media_c2_v1_video_decode_res"],
     test_config: "VtsHalMediaC2V1_0TargetVideoDecTest.xml",
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index c331d0b..95a4674 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -33,11 +33,18 @@
 #include <gui/IConsumerListener.h>
 #include <gui/IProducerListener.h>
 #include <system/window.h>
+#include <gui/GLConsumer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
 
 #include "media_c2_hidl_test_common.h"
 #include "media_c2_video_hidl_test_common.h"
 
-using DecodeTestParameters = std::tuple<std::string, std::string, uint32_t, bool>;
+constexpr size_t kSmoothnessFactor = 4;
+constexpr size_t kRenderingDepth = 3;
+enum surfaceMode_t { NO_SURFACE, NULL_SURFACE, SURFACE };
+
+using DecodeTestParameters = std::tuple<std::string, std::string, uint32_t, bool, surfaceMode_t>;
 static std::vector<DecodeTestParameters> gDecodeTestParameters;
 
 using CsdFlushTestParameters = std::tuple<std::string, std::string, bool>;
@@ -64,13 +71,15 @@
         {"3gpp", "bbb_h263_352x288_300kbps_12fps.h263", "bbb_h263_352x288_300kbps_12fps.info", ""},
         {"mp4v-es", "bbb_mpeg4_352x288_512kbps_30fps.m4v", "bbb_mpeg4_352x288_512kbps_30fps.info",
          ""},
-        {"vp8", "bbb_vp8_176x144_240kbps_60fps.vp8", "bbb_vp8_176x144_240kbps_60fps.info", ""},
-        {"vp8", "bbb_vp8_640x360_2mbps_30fps.vp8", "bbb_vp8_640x360_2mbps_30fps.info",
+        {"x-vnd.on2.vp8", "bbb_vp8_176x144_240kbps_60fps.vp8", "bbb_vp8_176x144_240kbps_60fps.info",
+         ""},
+        {"x-vnd.on2.vp8", "bbb_vp8_640x360_2mbps_30fps.vp8", "bbb_vp8_640x360_2mbps_30fps.info",
          "bbb_vp8_640x360_2mbps_30fps_chksm.md5"},
-        {"vp9", "bbb_vp9_176x144_285kbps_60fps.vp9", "bbb_vp9_176x144_285kbps_60fps.info", ""},
-        {"vp9", "bbb_vp9_640x360_1600kbps_30fps.vp9", "bbb_vp9_640x360_1600kbps_30fps.info",
-         "bbb_vp9_640x360_1600kbps_30fps_chksm.md5"},
-        {"vp9", "bbb_vp9_704x480_280kbps_24fps_altref_2.vp9",
+        {"x-vnd.on2.vp9", "bbb_vp9_176x144_285kbps_60fps.vp9", "bbb_vp9_176x144_285kbps_60fps.info",
+         ""},
+        {"x-vnd.on2.vp9", "bbb_vp9_640x360_1600kbps_30fps.vp9",
+         "bbb_vp9_640x360_1600kbps_30fps.info", "bbb_vp9_640x360_1600kbps_30fps_chksm.md5"},
+        {"x-vnd.on2.vp9", "bbb_vp9_704x480_280kbps_24fps_altref_2.vp9",
          "bbb_vp9_704x480_280kbps_24fps_altref_2.info", ""},
         {"av01", "bbb_av1_640_360.av1", "bbb_av1_640_360.info", "bbb_av1_640_360_chksum.md5"},
         {"av01", "bbb_av1_176_144.av1", "bbb_av1_176_144.info", "bbb_av1_176_144_chksm.md5"},
@@ -379,7 +388,7 @@
     int streamCount = 0;
 
     for (size_t i = 0; i < gCompToFiles.size(); ++i) {
-        if (mMime.find(gCompToFiles[i].mime) != std::string::npos) {
+        if (!mMime.compare("video/" + gCompToFiles[i].mime)) {
             if (streamCount == streamIndex) {
                 mInputFile = sResourceDir + gCompToFiles[i].inputFile;
                 mInfoFile = sResourceDir + gCompToFiles[i].infoFile;
@@ -392,6 +401,36 @@
     return false;
 }
 
+void setOutputSurface(const std::shared_ptr<android::Codec2Client::Component>& component,
+                      surfaceMode_t surfMode) {
+    using namespace android;
+    sp<IGraphicBufferProducer> producer = nullptr;
+    static std::atomic_uint32_t surfaceGeneration{0};
+    uint32_t generation =
+            (getpid() << 10) |
+            ((surfaceGeneration.fetch_add(1, std::memory_order_relaxed) + 1) & ((1 << 10) - 1));
+    int32_t maxDequeueBuffers = kSmoothnessFactor + kRenderingDepth;
+    if (surfMode == SURFACE) {
+        sp<IGraphicBufferConsumer> consumer = nullptr;
+        BufferQueue::createBufferQueue(&producer, &consumer);
+        ASSERT_NE(producer, nullptr) << "createBufferQueue returned invalid producer";
+        ASSERT_NE(consumer, nullptr) << "createBufferQueue returned invalid consumer";
+
+        sp<GLConsumer> texture =
+                new GLConsumer(consumer, 0 /* tex */, GLConsumer::TEXTURE_EXTERNAL,
+                               true /* useFenceSync */, false /* isControlledByApp */);
+
+        sp<ANativeWindow> gSurface = new Surface(producer);
+        ASSERT_NE(gSurface, nullptr) << "getSurface failed";
+
+        producer->setGenerationNumber(generation);
+    }
+
+    c2_status_t err = component->setOutputSurface(C2BlockPool::BASIC_GRAPHIC, producer, generation,
+                                                  maxDequeueBuffers);
+    ASSERT_EQ(err, C2_OK) << "setOutputSurface failed";
+}
+
 void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
                    std::mutex& queueLock, std::condition_variable& queueCondition,
                    std::list<std::unique_ptr<C2Work>>& workQueue,
@@ -550,6 +589,7 @@
     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
     bool signalEOS = std::get<3>(GetParam());
+    surfaceMode_t surfMode = std::get<4>(GetParam());
     mTimestampDevTest = true;
 
     android::Vector<FrameInfo> Info;
@@ -594,6 +634,10 @@
         refChksum.close();
     }
 
+    if (surfMode != NO_SURFACE) {
+        ASSERT_NO_FATAL_FAILURE(setOutputSurface(mComponent, surfMode));
+    }
+
     ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
                                           mFlushedIndices, mLinearPool, eleStream, &Info, 0,
                                           (int)Info.size(), signalEOS));
@@ -1061,18 +1105,23 @@
     parseArgs(argc, argv);
     gTestParameters = getTestParameters(C2Component::DOMAIN_VIDEO, C2Component::KIND_DECODER);
     for (auto params : gTestParameters) {
+        // mOutputBufferQueue->configure() crashes when surface is NULL
+        std::initializer_list<surfaceMode_t> surfaceMode = {
+                surfaceMode_t::NO_SURFACE, surfaceMode_t::NULL_SURFACE, surfaceMode_t::SURFACE};
+        for (surfaceMode_t mode : surfaceMode) {
+            gDecodeTestParameters.push_back(
+                    std::make_tuple(std::get<0>(params), std::get<1>(params), 0, false, mode));
+            gDecodeTestParameters.push_back(
+                    std::make_tuple(std::get<0>(params), std::get<1>(params), 0, true, mode));
+        }
         gDecodeTestParameters.push_back(
-                std::make_tuple(std::get<0>(params), std::get<1>(params), 0, false));
+                std::make_tuple(std::get<0>(params), std::get<1>(params), 1, false, NO_SURFACE));
         gDecodeTestParameters.push_back(
-                std::make_tuple(std::get<0>(params), std::get<1>(params), 0, true));
+                std::make_tuple(std::get<0>(params), std::get<1>(params), 1, true, NO_SURFACE));
         gDecodeTestParameters.push_back(
-                std::make_tuple(std::get<0>(params), std::get<1>(params), 1, false));
+                std::make_tuple(std::get<0>(params), std::get<1>(params), 2, false, NO_SURFACE));
         gDecodeTestParameters.push_back(
-                std::make_tuple(std::get<0>(params), std::get<1>(params), 1, true));
-        gDecodeTestParameters.push_back(
-                std::make_tuple(std::get<0>(params), std::get<1>(params), 2, false));
-        gDecodeTestParameters.push_back(
-                std::make_tuple(std::get<0>(params), std::get<1>(params), 2, true));
+                std::make_tuple(std::get<0>(params), std::get<1>(params), 2, true, NO_SURFACE));
 
         gCsdFlushTestParameters.push_back(
                 std::make_tuple(std::get<0>(params), std::get<1>(params), true));
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index 6a00edd..a6507e7 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -334,6 +334,12 @@
     int bytesCount = nWidth * nHeight * 3 >> 1;
     int32_t timestampIncr = ENCODER_TIMESTAMP_INCREMENT;
     c2_status_t err = C2_OK;
+
+    // Query component's memory usage flags
+    std::vector<std::unique_ptr<C2Param>> params;
+    C2StreamUsageTuning::input compUsage(0u, 0u);
+    component->query({&compUsage}, {}, C2_DONT_BLOCK, &params);
+
     while (1) {
         if (nFrames == 0) break;
         uint32_t flags = 0;
@@ -384,7 +390,8 @@
         }
         std::shared_ptr<C2GraphicBlock> block;
         err = graphicPool->fetchGraphicBlock(nWidth, nHeight, HAL_PIXEL_FORMAT_YV12,
-                                             {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
+                                             {C2MemoryUsage::CPU_READ | compUsage.value,
+                                                 C2MemoryUsage::CPU_WRITE | compUsage.value},
                                              &block);
         if (err != C2_OK) {
             fprintf(stderr, "fetchGraphicBlock failed : %d\n", err);
diff --git a/media/codec2/hidl/client/output.cpp b/media/codec2/hidl/client/output.cpp
index 8cd4934..de34c24 100644
--- a/media/codec2/hidl/client/output.cpp
+++ b/media/codec2/hidl/client/output.cpp
@@ -181,7 +181,7 @@
                                   int maxDequeueBufferCount,
                                   std::shared_ptr<V1_2::SurfaceSyncObj> *syncObj) {
     uint64_t consumerUsage = 0;
-    if (igbp->getConsumerUsage(&consumerUsage) != OK) {
+    if (igbp && igbp->getConsumerUsage(&consumerUsage) != OK) {
         ALOGW("failed to get consumer usage");
     }
 
@@ -254,6 +254,9 @@
         mBqId = bqId;
         mOwner = std::make_shared<int>(0);
         mMaxDequeueBufferCount = maxDequeueBufferCount;
+        if (igbp == nullptr) {
+            return false;
+        }
         for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; ++i) {
             if (mBqId == 0 || !mBuffers[i]) {
                 continue;
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 16398a4..db7b3b6 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1572,8 +1572,25 @@
 
     // configure dataspace
     static_assert(sizeof(int32_t) == sizeof(android_dataspace), "dataspace size mismatch");
-    android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN;
-    (void)config->mInputFormat->findInt32("android._dataspace", (int32_t*)&dataSpace);
+
+    // The output format contains app-configured color aspects, and the input format
+    // has the default color aspects. Use the default for the unspecified params.
+    ColorAspects inputColorAspects, outputColorAspects;
+    getColorAspectsFromFormat(config->mOutputFormat, outputColorAspects);
+    getColorAspectsFromFormat(config->mInputFormat, inputColorAspects);
+    if (outputColorAspects.mRange == ColorAspects::RangeUnspecified) {
+        outputColorAspects.mRange = inputColorAspects.mRange;
+    }
+    if (outputColorAspects.mPrimaries == ColorAspects::PrimariesUnspecified) {
+        outputColorAspects.mPrimaries = inputColorAspects.mPrimaries;
+    }
+    if (outputColorAspects.mTransfer == ColorAspects::TransferUnspecified) {
+        outputColorAspects.mTransfer = inputColorAspects.mTransfer;
+    }
+    if (outputColorAspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified) {
+        outputColorAspects.mMatrixCoeffs = inputColorAspects.mMatrixCoeffs;
+    }
+    android_dataspace dataSpace = getDataSpaceForColorAspects(outputColorAspects, false);
     surface->setDataSpace(dataSpace);
 
     status_t err = mChannel->setInputSurface(surface);
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index e7207a5..29cc564 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -1301,17 +1301,7 @@
 
 sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
     if (buffer == nullptr) {
-        sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
-                mFormat,
-                [lbp = mLocalBufferPool](size_t capacity) {
-                    return lbp->newBuffer(capacity);
-                });
-        if (c2buffer == nullptr) {
-            ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
-            return nullptr;
-        }
-        c2buffer->setRange(0, 0);
-        return c2buffer;
+        return new Codec2Buffer(mFormat, new ABuffer(nullptr, 0));
     } else {
         return ConstGraphicBlockBuffer::Allocate(
                 mFormat,
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 691bab1..4070478 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -491,7 +491,7 @@
                         * align(mHeight, 64) / plane.rowSampling;
             }
 
-            if ((maxPtr - minPtr + 1) <= planeSize) {
+            if (minPtr == mView.data()[0] && (maxPtr - minPtr + 1) <= planeSize) {
                 // FIXME: this is risky as reading/writing data out of bound results
                 //        in an undefined behavior, but gralloc does assume a
                 //        contiguous mapping
diff --git a/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp b/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp
index 66b7622..41e4fff 100644
--- a/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp
+++ b/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp
@@ -106,6 +106,19 @@
     }
 }
 
+TEST(RawGraphicOutputBuffersTest, WrapNullBuffer) {
+    constexpr int32_t kWidth = 320;
+    constexpr int32_t kHeight = 240;
+
+    std::shared_ptr<RawGraphicOutputBuffers> buffers =
+        GetRawGraphicOutputBuffers(kWidth, kHeight);
+
+    sp<Codec2Buffer> buffer = buffers->wrap(nullptr);
+    ASSERT_EQ(nullptr, buffer->base());
+    ASSERT_EQ(0, buffer->size());
+    ASSERT_EQ(0, buffer->offset());
+}
+
 TEST(RawGraphicOutputBuffersTest, FlexYuvColorFormat) {
     constexpr int32_t kWidth = 320;
     constexpr int32_t kHeight = 240;
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 1ed240a..09d9535 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -452,8 +452,8 @@
                                             void* threadArg)
 {
     if (mHasThread) {
-        ALOGE("%s() - mHasThread already true", __func__);
-        return AAUDIO_ERROR_INVALID_STATE;
+        ALOGD("%s() - previous thread was not joined, join now to be safe", __func__);
+        joinThread_l(nullptr);
     }
     if (threadProc == nullptr) {
         return AAUDIO_ERROR_NULL;
@@ -462,6 +462,7 @@
     mThreadProc = threadProc;
     mThreadArg = threadArg;
     setPeriodNanoseconds(periodNanoseconds);
+    mHasThread = true;
     // Prevent this object from getting deleted before the thread has a chance to create
     // its strong pointer. Assume the thread will call decStrong().
     this->incStrong(nullptr);
@@ -470,6 +471,7 @@
         android::status_t status = -errno;
         ALOGE("%s() - pthread_create() failed, %d", __func__, status);
         this->decStrong(nullptr); // Because the thread won't do it.
+        mHasThread = false;
         return AAudioConvert_androidToAAudioResult(status);
     } else {
         // TODO Use AAudioThread or maybe AndroidThread
@@ -484,7 +486,6 @@
         err = pthread_setname_np(mThread, name);
         ALOGW_IF((err != 0), "Could not set name of AAudio thread. err = %d", err);
 
-        mHasThread = true;
         return AAUDIO_OK;
     }
 }
@@ -498,7 +499,7 @@
 // This must be called under mStreamLock.
 aaudio_result_t AudioStream::joinThread_l(void** returnArg) {
     if (!mHasThread) {
-        ALOGD("joinThread() - but has no thread");
+        ALOGD("joinThread() - but has no thread or already join()ed");
         return AAUDIO_ERROR_INVALID_STATE;
     }
     aaudio_result_t result = AAUDIO_OK;
@@ -515,8 +516,7 @@
             result = AAudioConvert_androidToAAudioResult(-err);
         } else {
             ALOGD("%s() pthread_join succeeded", __func__);
-            // This must be set false so that the callback thread can be created
-            // when the stream is restarted.
+            // Prevent joining a second time, which has undefined behavior.
             mHasThread = false;
         }
     } else {
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 2b45ed3..9835c8c 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -157,9 +157,13 @@
 
     virtual aaudio_result_t setBufferSize(int32_t requestedFrames) = 0;
 
-    virtual aaudio_result_t createThread_l(int64_t periodNanoseconds,
-                                           aaudio_audio_thread_proc_t threadProc,
-                                           void *threadArg);
+    aaudio_result_t createThread(int64_t periodNanoseconds,
+                                 aaudio_audio_thread_proc_t threadProc,
+                                 void *threadArg)
+                                 EXCLUDES(mStreamLock) {
+        std::lock_guard<std::mutex> lock(mStreamLock);
+        return createThread_l(periodNanoseconds, threadProc, threadArg);
+    }
 
     aaudio_result_t joinThread(void **returnArg);
 
@@ -535,6 +539,11 @@
         mSessionId = sessionId;
     }
 
+    aaudio_result_t createThread_l(int64_t periodNanoseconds,
+                                           aaudio_audio_thread_proc_t threadProc,
+                                           void *threadArg)
+                                           REQUIRES(mStreamLock);
+
     aaudio_result_t joinThread_l(void **returnArg) REQUIRES(mStreamLock);
 
     std::atomic<bool>    mCallbackEnabled{false};
@@ -658,6 +667,7 @@
     std::atomic<pid_t>          mErrorCallbackThread{CALLBACK_THREAD_NONE};
 
     // background thread ----------------------------------
+    // Use mHasThread to prevent joining twice, which has undefined behavior.
     bool                        mHasThread GUARDED_BY(mStreamLock) = false;
     pthread_t                   mThread  GUARDED_BY(mStreamLock) = {};
 
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 6765bdb..5f802de 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -472,7 +472,7 @@
             status = BAD_VALUE;
             goto exit;
         }
-        mStreamType = streamType;
+        mOriginalStreamType = streamType;
 
     } else {
         // stream type shouldn't be looked at, this track has audio attributes
@@ -481,7 +481,7 @@
                 " usage=%d content=%d flags=0x%x tags=[%s]",
                 __func__,
                  mAttributes.usage, mAttributes.content_type, mAttributes.flags, mAttributes.tags);
-        mStreamType = AUDIO_STREAM_DEFAULT;
+        mOriginalStreamType = AUDIO_STREAM_DEFAULT;
         audio_flags_to_audio_output_flags(mAttributes.flags, &flags);
     }
 
@@ -1605,9 +1605,6 @@
 
 audio_stream_type_t AudioTrack::streamType() const
 {
-    if (mStreamType == AUDIO_STREAM_DEFAULT) {
-        return AudioSystem::attributesToStreamType(mAttributes);
-    }
     return mStreamType;
 }
 
@@ -1688,8 +1685,9 @@
     }
 
     IAudioFlinger::CreateTrackInput input;
-    if (mStreamType != AUDIO_STREAM_DEFAULT) {
-        input.attr = AudioSystem::streamTypeToAttributes(mStreamType);
+    if (mOriginalStreamType != AUDIO_STREAM_DEFAULT) {
+        // Legacy: This is based on original parameters even if the track is recreated.
+        input.attr = AudioSystem::streamTypeToAttributes(mOriginalStreamType);
     } else {
         input.attr = mAttributes;
     }
@@ -1745,6 +1743,7 @@
     mNotificationFramesAct = (uint32_t)output.notificationFrameCount;
     mRoutedDeviceId = output.selectedDeviceId;
     mSessionId = output.sessionId;
+    mStreamType = output.streamType;
 
     mSampleRate = output.sampleRate;
     if (mOriginalSampleRate == 0) {
@@ -3284,8 +3283,6 @@
     result.appendFormat("  id(%d) status(%d), state(%d), session Id(%d), flags(%#x)\n",
                         mPortId, mStatus, mState, mSessionId, mFlags);
     result.appendFormat("  stream type(%d), left - right volume(%f, %f)\n",
-                        (mStreamType == AUDIO_STREAM_DEFAULT) ?
-                            AudioSystem::attributesToStreamType(mAttributes) :
                             mStreamType,
                         mVolume[AUDIO_INTERLEAVE_LEFT], mVolume[AUDIO_INTERLEAVE_RIGHT]);
     result.appendFormat("  format(%#x), channel mask(%#x), channel count(%u)\n",
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 0564cdf..cae81f0 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -101,6 +101,8 @@
             legacy2aidl_audio_port_handle_t_int32_t(selectedDeviceId));
     aidl.sessionId = VALUE_OR_RETURN(legacy2aidl_audio_session_t_int32_t(sessionId));
     aidl.sampleRate = VALUE_OR_RETURN(convertIntegral<int32_t>(sampleRate));
+    aidl.streamType =  VALUE_OR_RETURN(
+            legacy2aidl_audio_stream_type_t_AudioStreamType(streamType));
     aidl.afFrameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(afFrameCount));
     aidl.afSampleRate = VALUE_OR_RETURN(convertIntegral<int32_t>(afSampleRate));
     aidl.afLatencyMs = VALUE_OR_RETURN(convertIntegral<int32_t>(afLatencyMs));
@@ -122,6 +124,8 @@
             aidl2legacy_int32_t_audio_port_handle_t(aidl.selectedDeviceId));
     legacy.sessionId = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_session_t(aidl.sessionId));
     legacy.sampleRate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.sampleRate));
+    legacy.streamType = VALUE_OR_RETURN(
+            aidl2legacy_AudioStreamType_audio_stream_type_t(aidl.streamType));
     legacy.afFrameCount = VALUE_OR_RETURN(convertIntegral<size_t>(aidl.afFrameCount));
     legacy.afSampleRate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.afSampleRate));
     legacy.afLatencyMs = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.afLatencyMs));
@@ -661,7 +665,11 @@
 status_t AudioFlingerClientAdapter::createAudioPatch(const struct audio_patch* patch,
                                                      audio_patch_handle_t* handle) {
     media::AudioPatch patchAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_patch_AudioPatch(*patch));
-    int32_t aidlRet;
+    int32_t aidlRet = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_patch_handle_t_int32_t(
+                    AUDIO_PATCH_HANDLE_NONE));
+    if (handle != nullptr) {
+        aidlRet = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_patch_handle_t_int32_t(*handle));
+    }
     RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
             mDelegate->createAudioPatch(patchAidl, &aidlRet)));
     if (handle != nullptr) {
@@ -1136,7 +1144,8 @@
 Status AudioFlingerServerAdapter::createAudioPatch(const media::AudioPatch& patch,
                                                    int32_t* _aidl_return) {
     audio_patch patchLegacy = VALUE_OR_RETURN_BINDER(aidl2legacy_AudioPatch_audio_patch(patch));
-    audio_patch_handle_t handleLegacy;
+    audio_patch_handle_t handleLegacy = VALUE_OR_RETURN_BINDER(
+            aidl2legacy_int32_t_audio_patch_handle_t(*_aidl_return));
     RETURN_BINDER_IF_ERROR(mDelegate->createAudioPatch(&patchLegacy, &handleLegacy));
     *_aidl_return = VALUE_OR_RETURN_BINDER(legacy2aidl_audio_patch_handle_t_int32_t(handleLegacy));
     return Status::ok();
diff --git a/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl b/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl
index 6bdd8e4..40473fa 100644
--- a/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl
+++ b/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import android.media.AudioStreamType;
 import android.media.IAudioTrack;
 
 /**
@@ -34,6 +35,7 @@
     int selectedDeviceId;
     int sessionId;
     int sampleRate;
+    AudioStreamType streamType;
     long afFrameCount;
     int afSampleRate;
     int afLatencyMs;
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index f61eef2..cb00990 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1164,8 +1164,9 @@
 
     // constant after constructor or set()
     audio_format_t          mFormat;                // as requested by client, not forced to 16-bit
-    audio_stream_type_t     mStreamType;            // mStreamType == AUDIO_STREAM_DEFAULT implies
-                                                    // this AudioTrack has valid attributes
+    // mOriginalStreamType == AUDIO_STREAM_DEFAULT implies this AudioTrack has valid attributes
+    audio_stream_type_t     mOriginalStreamType = AUDIO_STREAM_DEFAULT;
+    audio_stream_type_t     mStreamType = AUDIO_STREAM_DEFAULT;
     uint32_t                mChannelCount;
     audio_channel_mask_t    mChannelMask;
     sp<IMemory>             mSharedBuffer;
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 327b37e..0e059f7 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -110,6 +110,7 @@
 
         /* output */
         uint32_t sampleRate;
+        audio_stream_type_t streamType;
         size_t   afFrameCount;
         uint32_t afSampleRate;
         uint32_t afLatencyMs;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index d94cecf..9ae7ddb 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -2856,10 +2856,43 @@
 
     CHECK(msg->findInt32("payload-type", &payloadType));
 
+    int32_t rtpSeq = 0, rtpTime = 0;
+    int64_t ntpTime = 0, recvTimeUs = 0;
+
     Parcel in;
     in.writeInt32(payloadType);
 
     switch (payloadType) {
+        case ARTPSource::RTP_FIRST_PACKET:
+        {
+            CHECK(msg->findInt32("rtp-time", &rtpTime));
+            CHECK(msg->findInt32("rtp-seq-num", &rtpSeq));
+            CHECK(msg->findInt64("recv-time-us", &recvTimeUs));
+            in.writeInt32(rtpTime);
+            in.writeInt32(rtpSeq);
+            in.writeInt32(recvTimeUs >> 32);
+            in.writeInt32(recvTimeUs & 0xFFFFFFFF);
+            break;
+        }
+        case ARTPSource::RTCP_FIRST_PACKET:
+        {
+            CHECK(msg->findInt64("recv-time-us", &recvTimeUs));
+            in.writeInt32(recvTimeUs >> 32);
+            in.writeInt32(recvTimeUs & 0xFFFFFFFF);
+            break;
+        }
+        case ARTPSource::RTCP_SR:
+        {
+            CHECK(msg->findInt32("rtp-time", &rtpTime));
+            CHECK(msg->findInt64("ntp-time", &ntpTime));
+            CHECK(msg->findInt64("recv-time-us", &recvTimeUs));
+            in.writeInt32(rtpTime);
+            in.writeInt32(ntpTime >> 32);
+            in.writeInt32(ntpTime & 0xFFFFFFFF);
+            in.writeInt32(recvTimeUs >> 32);
+            in.writeInt32(recvTimeUs & 0xFFFFFFFF);
+            break;
+        }
         case ARTPSource::RTCP_TSFB:   // RTCP TSFB
         case ARTPSource::RTCP_PSFB:   // RTCP PSFB
         case ARTPSource::RTP_AUTODOWN:
@@ -2882,6 +2915,8 @@
             int32_t feedbackType, bitrate;
             int32_t highestSeqNum, baseSeqNum, prevExpected;
             int32_t numBufRecv, prevNumBufRecv;
+            int32_t latestRtpTime, jbTimeMs, rtpRtcpSrTimeGapMs;
+            int64_t recvTimeUs;
             CHECK(msg->findInt32("feedback-type", &feedbackType));
             CHECK(msg->findInt32("bit-rate", &bitrate));
             CHECK(msg->findInt32("highest-seq-num", &highestSeqNum));
@@ -2889,6 +2924,10 @@
             CHECK(msg->findInt32("prev-expected", &prevExpected));
             CHECK(msg->findInt32("num-buf-recv", &numBufRecv));
             CHECK(msg->findInt32("prev-num-buf-recv", &prevNumBufRecv));
+            CHECK(msg->findInt32("latest-rtp-time", &latestRtpTime));
+            CHECK(msg->findInt64("recv-time-us", &recvTimeUs));
+            CHECK(msg->findInt32("rtp-jitter-time-ms", &jbTimeMs));
+            CHECK(msg->findInt32("rtp-rtcpsr-time-gap-ms", &rtpRtcpSrTimeGapMs));
             in.writeInt32(feedbackType);
             in.writeInt32(bitrate);
             in.writeInt32(highestSeqNum);
@@ -2896,6 +2935,11 @@
             in.writeInt32(prevExpected);
             in.writeInt32(numBufRecv);
             in.writeInt32(prevNumBufRecv);
+            in.writeInt32(latestRtpTime);
+            in.writeInt32(recvTimeUs >> 32);
+            in.writeInt32(recvTimeUs & 0xFFFFFFFF);
+            in.writeInt32(jbTimeMs);
+            in.writeInt32(rtpRtcpSrTimeGapMs);
             break;
         }
         case ARTPSource::RTP_CVO:
diff --git a/media/libmediaplayerservice/nuplayer/RTPSource.cpp b/media/libmediaplayerservice/nuplayer/RTPSource.cpp
index d2d978a..4d6a483 100644
--- a/media/libmediaplayerservice/nuplayer/RTPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTPSource.cpp
@@ -395,23 +395,13 @@
                 CHECK(msg->findInt64("ntp-time", (int64_t *)&ntpTime));
 
                 onTimeUpdate(trackIndex, rtpTime, ntpTime);
-                break;
-            }
-
-            int32_t firstRTCP;
-            if (msg->findInt32("first-rtcp", &firstRTCP)) {
-                // There won't be an access unit here, it's just a notification
-                // that the data communication worked since we got the first
-                // rtcp packet.
-                ALOGV("first-rtcp");
-                break;
             }
 
             int32_t IMSRxNotice;
             if (msg->findInt32("rtcp-event", &IMSRxNotice)) {
-                int32_t payloadType, feedbackType;
+                int32_t payloadType = 0, feedbackType = 0;
                 CHECK(msg->findInt32("payload-type", &payloadType));
-                CHECK(msg->findInt32("feedback-type", &feedbackType));
+                msg->findInt32("feedback-type", &feedbackType);
 
                 sp<AMessage> notify = dupNotify();
                 notify->setInt32("what", kWhatIMSRxNotice);
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 9533ae5..8e05de8 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -145,15 +145,17 @@
         return;
     }
 
-    // Close socket before posting message to RTSPSource message handler.
-    if (mHandler != NULL) {
-        close(mHandler->getARTSPConnection()->getSocket());
-    }
-
     sp<AMessage> msg = new AMessage(kWhatDisconnect, this);
 
     sp<AMessage> dummy;
     msg->postAndAwaitResponse(&dummy);
+
+    // Close socket after posting message to RTSPSource message handler.
+    if (mHandler != NULL && mHandler->getARTSPConnection()->getSocket() >= 0) {
+        ALOGD("closing rtsp socket if not closed yet.");
+        close(mHandler->getARTSPConnection()->getSocket());
+    }
+
 }
 
 status_t NuPlayer::RTSPSource::feedMoreTSData() {
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index 7272a74..d21908f 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -50,6 +50,8 @@
 static constexpr int32_t kDefaultBitrateMbps = 10 * 1000 * 1000;
 // Default frame rate.
 static constexpr int32_t kDefaultFrameRate = 30;
+// Default codec complexity
+static constexpr int32_t kDefaultCodecComplexity = 1;
 
 template <typename T>
 void VideoTrackTranscoder::BlockingQueue<T>::push(T const& value, bool front) {
@@ -247,6 +249,7 @@
 
     SetDefaultFormatValueInt32(AMEDIAFORMAT_KEY_PRIORITY, encoderFormat, kDefaultCodecPriority);
     SetDefaultFormatValueInt32(AMEDIAFORMAT_KEY_FRAME_RATE, encoderFormat, kDefaultFrameRate);
+    SetDefaultFormatValueInt32(AMEDIAFORMAT_KEY_COMPLEXITY, encoderFormat, kDefaultCodecComplexity);
     AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, kColorFormatSurface);
 
     // Always encode without rotation. The rotation degree will be transferred directly to
diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp
index 5b724aa..b9fb041 100644
--- a/media/libstagefright/CodecBase.cpp
+++ b/media/libstagefright/CodecBase.cpp
@@ -40,4 +40,31 @@
     buf->size = size;
 }
 
+status_t CodecBase::querySupportedParameters(std::vector<std::string> *names) {
+    if (names == nullptr) {
+        return BAD_VALUE;
+    }
+    names->clear();
+    return OK;
+}
+
+status_t CodecBase::describeParameter(const std::string &, CodecParameterDescriptor *) {
+    return ERROR_UNSUPPORTED;
+}
+
+status_t CodecBase::subscribeToParameters(const std::vector<std::string> &names) {
+    if (names.empty()) {
+        return OK;
+    }
+    return ERROR_UNSUPPORTED;
+}
+
+status_t CodecBase::unsubscribeFromParameters(const std::vector<std::string> &names) {
+    if (names.empty()) {
+        return OK;
+    }
+    return ERROR_UNSUPPORTED;
+}
+
+
 } // namespace android
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index efb2f86..48721ec 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -252,9 +252,7 @@
      *         INVALID_OPERATION if already released;
      *         ERROR_UNSUPPORTED if not supported.
      */
-    virtual status_t querySupportedParameters([[maybe_unused]] std::vector<std::string> *names) {
-        return ERROR_UNSUPPORTED;
-    }
+    virtual status_t querySupportedParameters(std::vector<std::string> *names);
     /**
      * Fill |desc| with description of the parameter with |name|.
      *
@@ -267,10 +265,8 @@
      *         ERROR_UNSUPPORTED if not supported.
      */
     virtual status_t describeParameter(
-            [[maybe_unused]] const std::string &name,
-            [[maybe_unused]] CodecParameterDescriptor *desc) {
-        return ERROR_UNSUPPORTED;
-    }
+            const std::string &name,
+            CodecParameterDescriptor *desc);
     /**
      * Subscribe to parameters in |names| and get output format change event
      * when they change.
@@ -281,10 +277,7 @@
      *         INVALID_OPERATION if already released;
      *         ERROR_UNSUPPORTED if not supported.
      */
-    virtual status_t subscribeToParameters(
-            [[maybe_unused]] const std::vector<std::string> &names) {
-        return ERROR_UNSUPPORTED;
-    }
+    virtual status_t subscribeToParameters(const std::vector<std::string> &names);
     /**
      * Unsubscribe from parameters in |names| and no longer get
      * output format change event when they change.
@@ -295,10 +288,7 @@
      *         INVALID_OPERATION if already released;
      *         ERROR_UNSUPPORTED if not supported.
      */
-    virtual status_t unsubscribeFromParameters(
-            [[maybe_unused]] const std::vector<std::string> &names) {
-        return ERROR_UNSUPPORTED;
-    }
+    virtual status_t unsubscribeFromParameters(const std::vector<std::string> &names);
 
     typedef CodecBase *(*CreateCodecFunc)(void);
     typedef PersistentSurface *(*CreateInputSurfaceFunc)(void);
diff --git a/media/libstagefright/rtsp/AAVCAssembler.cpp b/media/libstagefright/rtsp/AAVCAssembler.cpp
index e1cc5ec..3f4d662 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AAVCAssembler.cpp
@@ -44,6 +44,7 @@
       mNextExpectedSeqNo(0),
       mAccessUnitDamaged(false),
       mFirstIFrameProvided(false),
+      mLastCvo(-1),
       mLastIFrameProvidedAtMs(0),
       mLastRtpTimeJitterDataUs(0),
       mWidth(0),
@@ -137,7 +138,7 @@
     }
     source->putInterArrivalJitterData(rtpTime, nowTimeUs);
 
-    const int64_t startTimeMs = source->mFirstSysTime / 1000;
+    const int64_t startTimeMs = source->mSysAnchorTime / 1000;
     const int64_t nowTimeMs = nowTimeUs / 1000;
     const int32_t staticJitterTimeMs = source->getStaticJitterTimeMs();
     const int32_t baseJitterTimeMs = source->getBaseJitterTimeMs();
@@ -195,33 +196,38 @@
 
     if (!isExpired) {
         ALOGV("buffering in jitter buffer.");
+        // set an alarm for jitter buffer time expiration.
+        // adding 1ms because jitter buffer time is keep changing.
+        int64_t expTimeUs = (RtpToMs(std::abs(diffTimeRtp), clockRate) + 1) * 1000;
+        source->setJbAlarmTime(nowTimeUs, expTimeUs);
         return NOT_ENOUGH_DATA;
     }
 
     if (isFirstLineBroken) {
-        if (isSecondLineBroken) {
-            int64_t totalDiffTimeMs = RtpToMs(diffTimeRtp + jitterTimeRtp, clockRate);
-            ALOGE("buffer too late... \t RTP diff from exp =%lld \t MS diff from stamp = %lld\t\t"
+        int64_t totalDiffTimeMs = RtpToMs(diffTimeRtp + jitterTimeRtp, clockRate);
+        String8 info;
+        info.appendFormat("RTP diff from exp =%lld \t MS diff from stamp = %lld\t\t"
                     "Seq# %d \t ExpSeq# %d \t"
                     "JitterMs %d + (%d + %d * %.3f)",
                     (long long)diffTimeRtp, (long long)totalDiffTimeMs,
                     buffer->int32Data(), mNextExpectedSeqNo,
                     jitterTimeMs, tryJbTimeMs, dynamicJbTimeMs, JITTER_MULTIPLE);
+        if (isSecondLineBroken) {
+            ALOGE("%s", info.string());
             printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
             printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);
 
-            mNextExpectedSeqNo = pickProperSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
         }  else {
-            ALOGW("=== WARNING === buffer arrived after %d + %d = %d ms === WARNING === ",
-                    jitterTimeMs, tryJbTimeMs, jitterTimeMs + tryJbTimeMs);
+            ALOGW("%s", info.string());
         }
     }
 
     if (mNextExpectedSeqNoValid) {
-        int32_t size = queue->size();
+        mNextExpectedSeqNo = pickStartSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
         int32_t cntRemove = deleteUnitUnderSeq(queue, mNextExpectedSeqNo);
 
         if (cntRemove > 0) {
+            int32_t size = queue->size();
             source->noticeAbandonBuffer(cntRemove);
             ALOGW("delete %d of %d buffers", cntRemove, size);
         }
@@ -441,7 +447,6 @@
     uint32_t rtpTimeStartAt;
     CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTimeStartAt));
     uint32_t startSeqNo = buffer->int32Data();
-    bool pFrame = nalType == 0x1;
 
     if (data[1] & 0x40) {
         // Huh? End bit also set on the first buffer.
@@ -451,8 +456,6 @@
         complete = true;
     } else {
         List<sp<ABuffer> >::iterator it = ++queue->begin();
-        int32_t connected = 1;
-        bool snapped = false;
         while (it != queue->end()) {
             ALOGV("sequence length %zu", totalCount);
 
@@ -463,33 +466,26 @@
 
             if ((uint32_t)buffer->int32Data() != expectedSeqNo) {
                 ALOGD("sequence not complete, expected seqNo %u, got %u, nalType %u",
-                     expectedSeqNo, (unsigned)buffer->int32Data(), nalType);
-                snapped = true;
-
-                if (!pFrame) {
-                    return WRONG_SEQUENCE_NUMBER;
-                }
-            }
-
-            if (!snapped) {
-                connected++;
+                     expectedSeqNo, (uint32_t)buffer->int32Data(), nalType);
             }
 
             uint32_t rtpTime;
             CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
-            if (size < 2
-                    || data[0] != indicator
+            if (size < 2) {
+                ALOGV("Ignoring malformed FU buffer.");
+                it = queue->erase(it);
+                continue;
+            }
+            if (data[0] != indicator
                     || (data[1] & 0x1f) != nalType
                     || (data[1] & 0x80)
                     || rtpTime != rtpTimeStartAt) {
-                ALOGV("Ignoring malformed FU buffer.");
-
-                // Delete the whole start of the FU.
-
-                mNextExpectedSeqNo = expectedSeqNo + 1;
-                deleteUnitUnderSeq(queue, mNextExpectedSeqNo);
-
-                return MALFORMED_PACKET;
+                // Assembler already have given enough time by jitter buffer
+                ALOGD("Seems another frame. Incomplete frame [%d ~ %d) \t %d FUs",
+                        startSeqNo, expectedSeqNo, (int)queue->distance(queue->begin(), it));
+                expectedSeqNo = (uint32_t)buffer->int32Data();
+                complete = true;
+                break;
             }
 
             totalSize += size - 2;
@@ -498,14 +494,6 @@
             expectedSeqNo = (uint32_t)buffer->int32Data() + 1;
 
             if (data[1] & 0x40) {
-                if (pFrame && !recycleUnit(startSeqNo, expectedSeqNo,
-                            connected, totalCount, 0.5f)) {
-                    mNextExpectedSeqNo = expectedSeqNo;
-                    deleteUnitUnderSeq(queue, mNextExpectedSeqNo);
-
-                    return MALFORMED_PACKET;
-                }
-
                 // This is the last fragment.
                 complete = true;
                 break;
@@ -557,6 +545,9 @@
 
     if (cvo >= 0) {
         unit->meta()->setInt32("cvo", cvo);
+        mLastCvo = cvo;
+    } else if (mLastCvo >= 0) {
+        unit->meta()->setInt32("cvo", mLastCvo);
     }
     if (source != nullptr) {
         unit->meta()->setObject("source", source);
@@ -621,35 +612,32 @@
     msg->post();
 }
 
-int32_t AAVCAssembler::pickProperSeq(const Queue *queue,
+int32_t AAVCAssembler::pickStartSeq(const Queue *queue,
         uint32_t first, int64_t play, int64_t jit) {
+    // pick the first sequence number has the start bit.
     sp<ABuffer> buffer = *(queue->begin());
-    int32_t nextSeqNo = buffer->int32Data();
+    int32_t firstSeqNo = buffer->int32Data();
 
-    Queue::const_iterator it = queue->begin();
-    while (it != queue->end()) {
-        int64_t rtpTime = findRTPTime(first, *it);
-        // if pkt in time exists, that should be the next pivot
+    // This only works for FU-A type & non-start sequence
+    unsigned nalType = buffer->data()[0] & 0x1f;
+    if (nalType != 28 || buffer->data()[1] & 0x80) {
+        return firstSeqNo;
+    }
+
+    for (auto it : *queue) {
+        const uint8_t *data = it->data();
+        int64_t rtpTime = findRTPTime(first, it);
         if (rtpTime + jit >= play) {
-            nextSeqNo = (*it)->int32Data();
             break;
         }
-        it++;
+        if ((data[1] & 0x80)) {
+            const int32_t seqNo = it->int32Data();
+            ALOGE("finding [HEAD] pkt. \t Seq# (%d ~ )[%d", firstSeqNo, seqNo);
+            firstSeqNo = seqNo;
+            break;
+        }
     }
-    return nextSeqNo;
-}
-
-bool AAVCAssembler::recycleUnit(uint32_t start, uint32_t end, uint32_t connected,
-        size_t avail, float goodRatio) {
-    float total = end - start;
-    float valid = connected;
-    float exist = avail;
-    bool isRecycle = (valid / total) >= goodRatio;
-
-    ALOGV("checking p-frame losses.. recvBufs %f valid %f diff %f recycle? %d",
-            exist, valid, total, isRecycle);
-
-    return isRecycle;
+    return firstSeqNo;
 }
 
 int32_t AAVCAssembler::deleteUnitUnderSeq(Queue *queue, uint32_t seq) {
diff --git a/media/libstagefright/rtsp/AAVCAssembler.h b/media/libstagefright/rtsp/AAVCAssembler.h
index 8d19773..2f8b8ba 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.h
+++ b/media/libstagefright/rtsp/AAVCAssembler.h
@@ -22,6 +22,7 @@
 
 #include <utils/List.h>
 #include <utils/RefBase.h>
+#include <utils/String8.h>
 
 namespace android {
 
@@ -47,6 +48,7 @@
     uint32_t mNextExpectedSeqNo;
     bool mAccessUnitDamaged;
     bool mFirstIFrameProvided;
+    int32_t mLastCvo;
     uint64_t mLastIFrameProvidedAtMs;
     int64_t mLastRtpTimeJitterDataUs;
     int32_t mWidth;
@@ -64,9 +66,7 @@
 
     void submitAccessUnit();
 
-    int32_t pickProperSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
-    bool recycleUnit(uint32_t start, uint32_t end, uint32_t connected,
-            size_t avail, float goodRatio);
+    int32_t pickStartSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
     int32_t deleteUnitUnderSeq(Queue *q, uint32_t seq);
 
     DISALLOW_EVIL_CONSTRUCTORS(AAVCAssembler);
diff --git a/media/libstagefright/rtsp/AHEVCAssembler.cpp b/media/libstagefright/rtsp/AHEVCAssembler.cpp
index d32e85d..b240339 100644
--- a/media/libstagefright/rtsp/AHEVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AHEVCAssembler.cpp
@@ -51,6 +51,7 @@
       mNextExpectedSeqNo(0),
       mAccessUnitDamaged(false),
       mFirstIFrameProvided(false),
+      mLastCvo(-1),
       mLastIFrameProvidedAtMs(0),
       mLastRtpTimeJitterDataUs(0),
       mWidth(0),
@@ -147,7 +148,7 @@
     }
     source->putInterArrivalJitterData(rtpTime, nowTimeUs);
 
-    const int64_t startTimeMs = source->mFirstSysTime / 1000;
+    const int64_t startTimeMs = source->mSysAnchorTime / 1000;
     const int64_t nowTimeMs = nowTimeUs / 1000;
     const int32_t staticJitterTimeMs = source->getStaticJitterTimeMs();
     const int32_t baseJitterTimeMs = source->getBaseJitterTimeMs();
@@ -205,33 +206,38 @@
 
     if (!isExpired) {
         ALOGV("buffering in jitter buffer.");
+        // set an alarm for jitter buffer time expiration.
+        // adding 1ms because jitter buffer time is keep changing.
+        int64_t expTimeUs = (RtpToMs(std::abs(diffTimeRtp), clockRate) + 1) * 1000;
+        source->setJbAlarmTime(nowTimeUs, expTimeUs);
         return NOT_ENOUGH_DATA;
     }
 
     if (isFirstLineBroken) {
-        if (isSecondLineBroken) {
-            int64_t totalDiffTimeMs = RtpToMs(diffTimeRtp + jitterTimeRtp, clockRate);
-            ALOGE("buffer too late... \t RTP diff from exp =%lld \t MS diff from stamp = %lld\t\t"
+        int64_t totalDiffTimeMs = RtpToMs(diffTimeRtp + jitterTimeRtp, clockRate);
+        String8 info;
+        info.appendFormat("RTP diff from exp =%lld \t MS diff from stamp = %lld\t\t"
                     "Seq# %d \t ExpSeq# %d \t"
                     "JitterMs %d + (%d + %d * %.3f)",
                     (long long)diffTimeRtp, (long long)totalDiffTimeMs,
                     buffer->int32Data(), mNextExpectedSeqNo,
                     jitterTimeMs, tryJbTimeMs, dynamicJbTimeMs, JITTER_MULTIPLE);
+        if (isSecondLineBroken) {
+            ALOGE("%s", info.string());
             printNowTimeMs(startTimeMs, nowTimeMs, playedTimeMs);
             printRTPTime(rtpTime, playedTimeRtp, expiredTimeRtp, isExpired);
 
-            mNextExpectedSeqNo = pickProperSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
         }  else {
-            ALOGW("=== WARNING === buffer arrived after %d + %d = %d ms === WARNING === ",
-                    jitterTimeMs, tryJbTimeMs, jitterTimeMs + tryJbTimeMs);
+            ALOGW("%s", info.string());
         }
     }
 
     if (mNextExpectedSeqNoValid) {
-        int32_t size = queue->size();
+        mNextExpectedSeqNo = pickStartSeq(queue, firstRTPTime, playedTimeRtp, jitterTimeRtp);
         int32_t cntRemove = deleteUnitUnderSeq(queue, mNextExpectedSeqNo);
 
         if (cntRemove > 0) {
+            int32_t size = queue->size();
             source->noticeAbandonBuffer(cntRemove);
             ALOGW("delete %d of %d buffers", cntRemove, size);
         }
@@ -466,7 +472,6 @@
     uint32_t rtpTimeStartAt;
     CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTimeStartAt));
     uint32_t startSeqNo = buffer->int32Data();
-    bool pFrame = (nalType < 0x10);
 
     if (data[2] & 0x40) {
         // Huh? End bit also set on the first buffer.
@@ -476,8 +481,6 @@
         complete = true;
     } else {
         List<sp<ABuffer> >::iterator it = ++queue->begin();
-        int32_t connected = 1;
-        bool snapped = false;
         while (it != queue->end()) {
             ALOGV("sequence length %zu", totalCount);
 
@@ -488,33 +491,26 @@
 
             if ((uint32_t)buffer->int32Data() != expectedSeqNo) {
                 ALOGV("sequence not complete, expected seqNo %u, got %u, nalType %u",
-                     expectedSeqNo, (uint32_t)buffer->int32Data(), nalType);
-                snapped = true;
-
-                if (!pFrame) {
-                    return WRONG_SEQUENCE_NUMBER;
-                }
-            }
-
-            if (!snapped) {
-                connected++;
+                     expectedSeqNo, (unsigned)buffer->int32Data(), nalType);
             }
 
             uint32_t rtpTime;
             CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
-            if (size < 3
-                    || ((data[0] >> 1) & H265_NALU_MASK) != indicator
+            if (size < 3) {
+                ALOGV("Ignoring malformed FU buffer.");
+                it = queue->erase(it);
+                continue;
+            }
+            if (((data[0] >> 1) & H265_NALU_MASK) != indicator
                     || (data[2] & H265_NALU_MASK) != nalType
                     || (data[2] & 0x80)
                     || rtpTime != rtpTimeStartAt) {
-                ALOGV("Ignoring malformed FU buffer.");
-
-                // Delete the whole start of the FU.
-
-                mNextExpectedSeqNo = expectedSeqNo + 1;
-                deleteUnitUnderSeq(queue, mNextExpectedSeqNo);
-
-                return MALFORMED_PACKET;
+                // Assembler already have given enough time by jitter buffer
+                ALOGD("Seems another frame. Incomplete frame [%d ~ %d) \t %d FUs",
+                        startSeqNo, expectedSeqNo, (int)queue->distance(queue->begin(), it));
+                expectedSeqNo = (uint32_t)buffer->int32Data();
+                complete = true;
+                break;
             }
 
             totalSize += size - 3;
@@ -523,13 +519,6 @@
             expectedSeqNo = (uint32_t)buffer->int32Data() + 1;
 
             if (data[2] & 0x40) {
-                if (pFrame && !recycleUnit(startSeqNo, expectedSeqNo,
-                        connected, totalCount, 0.5f)) {
-                    mNextExpectedSeqNo = expectedSeqNo;
-                    deleteUnitUnderSeq(queue, mNextExpectedSeqNo);
-
-                    return MALFORMED_PACKET;
-                }
                 // This is the last fragment.
                 complete = true;
                 break;
@@ -579,6 +568,9 @@
 
     if (cvo >= 0) {
         unit->meta()->setInt32("cvo", cvo);
+        mLastCvo = cvo;
+    } else if (mLastCvo >= 0) {
+        unit->meta()->setInt32("cvo", mLastCvo);
     }
 
     addSingleNALUnit(unit);
@@ -635,35 +627,32 @@
     msg->post();
 }
 
-int32_t AHEVCAssembler::pickProperSeq(const Queue *queue,
+int32_t AHEVCAssembler::pickStartSeq(const Queue *queue,
         uint32_t first, int64_t play, int64_t jit) {
+    // pick the first sequence number has the start bit.
     sp<ABuffer> buffer = *(queue->begin());
-    int32_t nextSeqNo = buffer->int32Data();
+    int32_t firstSeqNo = buffer->int32Data();
 
-    Queue::const_iterator it = queue->begin();
-    while (it != queue->end()) {
-        int64_t rtpTime = findRTPTime(first, *it);
-        // if pkt in time exists, that should be the next pivot
+    // This only works for FU-A type & non-start sequence
+    unsigned nalType = buffer->data()[0] & 0x1f;
+    if (nalType != 28 || buffer->data()[2] & 0x80) {
+        return firstSeqNo;
+    }
+
+    for (auto it : *queue) {
+        const uint8_t *data = it->data();
+        int64_t rtpTime = findRTPTime(first, it);
         if (rtpTime + jit >= play) {
-            nextSeqNo = (*it)->int32Data();
             break;
         }
-        it++;
+        if ((data[2] & 0x80)) {
+            const int32_t seqNo = it->int32Data();
+            ALOGE("finding [HEAD] pkt. \t Seq# (%d ~ )[%d", firstSeqNo, seqNo);
+            firstSeqNo = seqNo;
+            break;
+        }
     }
-    return nextSeqNo;
-}
-
-bool AHEVCAssembler::recycleUnit(uint32_t start, uint32_t end,  uint32_t connected,
-         size_t avail, float goodRatio) {
-    float total = end - start;
-    float valid = connected;
-    float exist = avail;
-    bool isRecycle = (valid / total) >= goodRatio;
-
-    ALOGV("checking p-frame losses.. recvBufs %f valid %f diff %f recycle? %d",
-            exist, valid, total, isRecycle);
-
-    return isRecycle;
+    return firstSeqNo;
 }
 
 int32_t AHEVCAssembler::deleteUnitUnderSeq(Queue *queue, uint32_t seq) {
diff --git a/media/libstagefright/rtsp/AHEVCAssembler.h b/media/libstagefright/rtsp/AHEVCAssembler.h
index 68777a7..9575d8c 100644
--- a/media/libstagefright/rtsp/AHEVCAssembler.h
+++ b/media/libstagefright/rtsp/AHEVCAssembler.h
@@ -22,6 +22,7 @@
 
 #include <utils/List.h>
 #include <utils/RefBase.h>
+#include <utils/String8.h>
 
 namespace android {
 
@@ -48,6 +49,7 @@
     uint32_t mNextExpectedSeqNo;
     bool mAccessUnitDamaged;
     bool mFirstIFrameProvided;
+    int32_t mLastCvo;
     uint64_t mLastIFrameProvidedAtMs;
     int64_t mLastRtpTimeJitterDataUs;
     int32_t mWidth;
@@ -65,9 +67,7 @@
 
     void submitAccessUnit();
 
-    int32_t pickProperSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
-    bool recycleUnit(uint32_t start, uint32_t end, uint32_t connected,
-             size_t avail, float goodRatio);
+    int32_t pickStartSeq(const Queue *q, uint32_t first, int64_t play, int64_t jit);
     int32_t deleteUnitUnderSeq(Queue *queue, uint32_t seq);
 
     DISALLOW_EVIL_CONSTRUCTORS(AHEVCAssembler);
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 8f4df8e..169df46 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -594,4 +594,15 @@
     return mFormat;
 }
 
+bool APacketSource::isVideo() {
+    bool isVideo = false;
+
+    const char *mime;
+    if (mFormat->findCString(kKeyMIMEType, &mime)) {
+        isVideo = !strncasecmp(mime, "video/", 6);
+    }
+
+    return isVideo;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/rtsp/APacketSource.h b/media/libstagefright/rtsp/APacketSource.h
index 530e537..2b9b5ba 100644
--- a/media/libstagefright/rtsp/APacketSource.h
+++ b/media/libstagefright/rtsp/APacketSource.h
@@ -33,6 +33,8 @@
 
     virtual sp<MetaData> getFormat();
 
+    bool isVideo();
+
 protected:
     virtual ~APacketSource();
 
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 33c85a7..ffccbb1 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -18,9 +18,7 @@
 #define LOG_TAG "ARTPConnection"
 #include <utils/Log.h>
 
-#include "ARTPAssembler.h"
 #include "ARTPConnection.h"
-
 #include "ARTPSource.h"
 #include "ASessionDescription.h"
 
@@ -104,6 +102,11 @@
     msg->post();
 }
 
+void ARTPConnection::seekStream() {
+    sp<AMessage> msg = new AMessage(kWhatSeekStream, this);
+    msg->post();
+}
+
 void ARTPConnection::removeStream(int rtpSocket, int rtcpSocket) {
     sp<AMessage> msg = new AMessage(kWhatRemoveStream, this);
     msg->setInt32("rtp-socket", rtpSocket);
@@ -283,6 +286,12 @@
             break;
         }
 
+        case kWhatSeekStream:
+        {
+            onSeekStream(msg);
+            break;
+        }
+
         case kWhatRemoveStream:
         {
             onRemoveStream(msg);
@@ -295,6 +304,12 @@
             break;
         }
 
+        case kWhatAlarmStream:
+        {
+            onAlarmStream(msg);
+            break;
+        }
+
         case kWhatInjectPacket:
         {
             onInjectPacket(msg);
@@ -353,6 +368,18 @@
     }
 }
 
+void ARTPConnection::onSeekStream(const sp<AMessage> &msg) {
+    (void)msg; // unused param as of now.
+    List<StreamInfo>::iterator it = mStreams.begin();
+    while (it != mStreams.end()) {
+        for (size_t i = 0; i < it->mSources.size(); ++i) {
+            sp<ARTPSource> source = it->mSources.valueAt(i);
+            source->timeReset();
+        }
+        ++it;
+    }
+}
+
 void ARTPConnection::onRemoveStream(const sp<AMessage> &msg) {
     int32_t rtpSocket, rtcpSocket;
     CHECK(msg->findInt32("rtp-socket", &rtpSocket));
@@ -440,14 +467,16 @@
 
             if (err == -ECONNRESET) {
                 // socket failure, this stream is dead, Jim.
-                sp<AMessage> notify = it->mNotifyMsg->dup();
-                notify->setInt32("rtcp-event", 1);
-                notify->setInt32("payload-type", 400);
-                notify->setInt32("feedback-type", 1);
-                notify->setInt32("sender", it->mSources.valueAt(0)->getSelfID());
-                notify->post();
+                for (size_t i = 0; i < it->mSources.size(); ++i) {
+                    sp<AMessage> notify = it->mNotifyMsg->dup();
+                    notify->setInt32("rtcp-event", 1);
+                    notify->setInt32("payload-type", 400);
+                    notify->setInt32("feedback-type", 1);
+                    notify->setInt32("sender", it->mSources.valueAt(i)->getSelfID());
+                    notify->post();
 
-                ALOGW("failed to receive RTP/RTCP datagram.");
+                    ALOGW("failed to receive RTP/RTCP datagram.");
+                }
                 it = mStreams.erase(it);
                 continue;
             }
@@ -548,6 +577,13 @@
     }
 }
 
+void ARTPConnection::onAlarmStream(const sp<AMessage> msg) {
+    sp<ARTPSource> source = nullptr;
+    if (msg->findObject("source", (sp<android::RefBase>*)&source)) {
+        source->processRTPPacket();
+    }
+}
+
 status_t ARTPConnection::receive(StreamInfo *s, bool receiveRTP) {
     ALOGV("receiving %s", receiveRTP ? "RTP" : "RTCP");
 
@@ -633,12 +669,6 @@
 }
 
 status_t ARTPConnection::parseRTP(StreamInfo *s, const sp<ABuffer> &buffer) {
-    if (s->mNumRTPPacketsReceived++ == 0) {
-        sp<AMessage> notify = s->mNotifyMsg->dup();
-        notify->setInt32("first-rtp", true);
-        notify->post();
-    }
-
     size_t size = buffer->size();
 
     if (size < 12) {
@@ -720,9 +750,23 @@
         meta->setInt32("cvo", cvoDegrees);
     }
 
-    buffer->setInt32Data(u16at(&data[2]));
+    int32_t seq = u16at(&data[2]);
+    buffer->setInt32Data(seq);
     buffer->setRange(payloadOffset, size - payloadOffset);
 
+    if (s->mNumRTPPacketsReceived++ == 0) {
+        sp<AMessage> notify = s->mNotifyMsg->dup();
+        notify->setInt32("first-rtp", true);
+        notify->setInt32("rtcp-event", 1);
+        notify->setInt32("payload-type", ARTPSource::RTP_FIRST_PACKET);
+        notify->setInt32("rtp-time", (int32_t)rtpTime);
+        notify->setInt32("rtp-seq-num", seq);
+        notify->setInt64("recv-time-us", ALooper::GetNowUs());
+        notify->post();
+
+        ALOGD("send first-rtp event to upper layer");
+    }
+
     source->processRTPPacket(buffer);
 
     return OK;
@@ -779,14 +823,12 @@
     if (s->mNumRTCPPacketsReceived++ == 0) {
         sp<AMessage> notify = s->mNotifyMsg->dup();
         notify->setInt32("first-rtcp", true);
+        notify->setInt32("rtcp-event", 1);
+        notify->setInt32("payload-type", ARTPSource::RTCP_FIRST_PACKET);
+        notify->setInt64("recv-time-us", ALooper::GetNowUs());
         notify->post();
 
-        ALOGI("send first-rtcp event to upper layer as ImsRxNotice");
-        sp<AMessage> imsNotify = s->mNotifyMsg->dup();
-        imsNotify->setInt32("rtcp-event", 1);
-        imsNotify->setInt32("payload-type", 101);
-        imsNotify->setInt32("feedback-type", 0);
-        imsNotify->post();
+        ALOGD("send first-rtcp event to upper layer");
     }
 
     const uint8_t *data = buffer->data();
@@ -883,7 +925,7 @@
     int64_t nowUs = ALooper::GetNowUs();
     int32_t timeDiff = (nowUs - mLastBitrateReportTimeUs) / 1000000ll;
     int32_t bitrate = mCumulativeBytes * 8 / timeDiff;
-    source->notifyPktInfo(bitrate, true /* isRegular */);
+    source->notifyPktInfo(bitrate, nowUs, true /* isRegular */);
 
     source->byeReceived();
 
@@ -1065,11 +1107,14 @@
                 srcId, info->mSessionDesc, info->mIndex, info->mNotifyMsg);
 
         if (mFlags & kViLTEConnection) {
+            setStaticJitterTimeMs(50);
             source->setPeriodicFIR(false);
         }
 
         source->setSelfID(mSelfID);
         source->setStaticJitterTimeMs(mStaticJitterTimeMs);
+        sp<AMessage> timer = new AMessage(kWhatAlarmStream, this);
+        source->setJbTimer(timer);
         info->mSources.add(srcId, source);
     } else {
         source = info->mSources.valueAt(index);
@@ -1117,7 +1162,7 @@
             for (size_t i = 0; i < s->mSources.size(); ++i) {
                 sp<ARTPSource> source = s->mSources.valueAt(i);
                 if (source->isNeedToEarlyNotify()) {
-                    source->notifyPktInfo(bitrate, false /* isRegular */);
+                    source->notifyPktInfo(bitrate, nowUs, false /* isRegular */);
                     mLastEarlyNotifyTimeUs = nowUs + (1000000ll * 3600 * 24); // after 1 day
                 }
             }
@@ -1148,7 +1193,7 @@
             buffer->setRange(0, 0);
             for (size_t i = 0; i < s->mSources.size(); ++i) {
                 sp<ARTPSource> source = s->mSources.valueAt(i);
-                source->notifyPktInfo(bitrate, true /* isRegular */);
+                source->notifyPktInfo(bitrate, nowUs, true /* isRegular */);
             }
             ++it;
         }
diff --git a/media/libstagefright/rtsp/ARTPConnection.h b/media/libstagefright/rtsp/ARTPConnection.h
index ea0a374..36cca31 100644
--- a/media/libstagefright/rtsp/ARTPConnection.h
+++ b/media/libstagefright/rtsp/ARTPConnection.h
@@ -40,7 +40,7 @@
             const sp<ASessionDescription> &sessionDesc, size_t index,
             const sp<AMessage> &notify,
             bool injected);
-
+    void seekStream();
     void removeStream(int rtpSocket, int rtcpSocket);
 
     void injectPacket(int index, const sp<ABuffer> &buffer);
@@ -69,9 +69,11 @@
 private:
     enum {
         kWhatAddStream,
+        kWhatSeekStream,
         kWhatRemoveStream,
         kWhatPollStreams,
         kWhatInjectPacket,
+        kWhatAlarmStream,
     };
 
     static const int64_t kSelectTimeoutUs;
@@ -94,8 +96,10 @@
     int32_t mCumulativeBytes;
 
     void onAddStream(const sp<AMessage> &msg);
+    void onSeekStream(const sp<AMessage> &msg);
     void onRemoveStream(const sp<AMessage> &msg);
     void onPollStreams();
+    void onAlarmStream(const sp<AMessage> msg);
     void onInjectPacket(const sp<AMessage> &msg);
     void onSendReceiverReports();
     void checkRxBitrate(int64_t nowUs);
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index 8787d65..38a370b 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -44,10 +44,11 @@
         uint32_t id,
         const sp<ASessionDescription> &sessionDesc, size_t index,
         const sp<AMessage> &notify)
-    : mFirstSeqNumber(0),
-      mFirstRtpTime(0),
+    : mFirstRtpTime(0),
       mFirstSysTime(0),
       mClockRate(0),
+      mSysAnchorTime(0),
+      mLastSysAnchorTimeUpdatedUs(0),
       mFirstSsrc(0),
       mHighestNackNumber(0),
       mID(id),
@@ -58,9 +59,14 @@
       mPrevNumBuffersReceived(0),
       mPrevExpectedForRR(0),
       mPrevNumBuffersReceivedForRR(0),
+      mLatestRtpTime(0),
       mStaticJbTimeMs(kStaticJitterTimeMs),
-      mLastNTPTime(0),
-      mLastNTPTimeUpdateUs(0),
+      mLastSrRtpTime(0),
+      mLastSrNtpTime(0),
+      mLastSrUpdateTimeUs(0),
+      mIsFirstRtpRtcpGap(true),
+      mAvgRtpRtcpGapMs(0),
+      mAvgUnderlineDelayMs(0),
       mIssueFIRRequests(false),
       mIssueFIRByAssembler(false),
       mLastFIRRequestUs(-1),
@@ -106,6 +112,7 @@
     int32_t clockRate, numChannels;
     ASessionDescription::ParseFormatDesc(desc.c_str(), &clockRate, &numChannels);
     mClockRate = clockRate;
+    mLastJbAlarmTimeUs = 0;
     mJitterCalc = new JitterCalc(mClockRate);
 }
 
@@ -119,34 +126,144 @@
     }
 }
 
+void ARTPSource::processRTPPacket() {
+    if (mAssembler != NULL && !mQueue.empty()) {
+        mAssembler->onPacketReceived(this);
+    }
+}
+
 void ARTPSource::timeUpdate(uint32_t rtpTime, uint64_t ntpTime) {
-    mLastNTPTime = ntpTime;
-    mLastNTPTimeUpdateUs = ALooper::GetNowUs();
+    mLastSrRtpTime = rtpTime;
+    mLastSrNtpTime = ntpTime;
+    mLastSrUpdateTimeUs = ALooper::GetNowUs();
 
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("time-update", true);
     notify->setInt32("rtp-time", rtpTime);
     notify->setInt64("ntp-time", ntpTime);
+    notify->setInt32("rtcp-event", 1);
+    notify->setInt32("payload-type", RTCP_SR);
+    notify->setInt64("recv-time-us", mLastSrUpdateTimeUs);
     notify->post();
 }
 
-bool ARTPSource::queuePacket(const sp<ABuffer> &buffer) {
-    uint32_t seqNum = (uint32_t)buffer->int32Data();
+void ARTPSource::timeReset() {
+    mFirstRtpTime = 0;
+    mFirstSysTime = 0;
+    mSysAnchorTime = 0;
+    mLastSysAnchorTimeUpdatedUs = 0;
+    mFirstSsrc = 0;
+    mHighestNackNumber = 0;
+    mHighestSeqNumber = 0;
+    mPrevExpected = 0;
+    mBaseSeqNumber = 0;
+    mNumBuffersReceived = 0;
+    mPrevNumBuffersReceived = 0;
+    mPrevExpectedForRR = 0;
+    mPrevNumBuffersReceivedForRR = 0;
+    mLatestRtpTime = 0;
+    mLastSrRtpTime = 0;
+    mLastSrNtpTime = 0;
+    mLastSrUpdateTimeUs = 0;
+    mIsFirstRtpRtcpGap = true;
+    mAvgRtpRtcpGapMs = 0;
+    mAvgUnderlineDelayMs = 0;
+    mIssueFIRByAssembler = false;
+    mLastFIRRequestUs = -1;
+}
 
-    int32_t ssrc = 0;
+void ARTPSource::calcTimeGapRtpRtcp(const sp<ABuffer> &buffer, int64_t nowUs) {
+    if (mLastSrUpdateTimeUs == 0) {
+        return;
+    }
+
+    int64_t elapsedMs = (nowUs - mLastSrUpdateTimeUs) / 1000;
+    int64_t elapsedRtpTime = (elapsedMs * (mClockRate / 1000));
+    uint32_t rtpTime;
+    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+
+    int64_t anchorRtpTime = mLastSrRtpTime + elapsedRtpTime;
+    int64_t rtpTimeGap = anchorRtpTime - rtpTime;
+    // rtpTime can not be faster than it's anchor time.
+    // because rtpTime(of rtp packet) represents it's a frame captured time and
+    // anchorRtpTime(of rtcp:sr packet) represents it's a rtp packetized time.
+    if (rtpTimeGap < 0 || rtpTimeGap > (mClockRate * 60)) {
+        // ignore invalid delay gap such as negative delay or later than 1 min.
+        return;
+    }
+
+    int64_t rtpTimeGapMs = (rtpTimeGap * 1000 / mClockRate);
+    if (mIsFirstRtpRtcpGap) {
+        mIsFirstRtpRtcpGap = false;
+        mAvgRtpRtcpGapMs = rtpTimeGapMs;
+    } else {
+        // This is measuring avg rtp timestamp distance between rtp and rtcp:sr packet.
+        // Rtp timestamp of rtp packet represents it's raw frame captured time.
+        // Rtp timestamp of rtcp:sr packet represents it's packetization time.
+        // So that, this value is showing how much time delayed to be a rtp packet
+        // from a raw frame captured time.
+        // This value maybe referred to know a/v sync and sender's own delay of this media stream.
+        mAvgRtpRtcpGapMs = ((mAvgRtpRtcpGapMs * 15) + rtpTimeGapMs) / 16;
+    }
+}
+
+void ARTPSource::calcUnderlineDelay(const sp<ABuffer> &buffer, int64_t nowUs) {
+    int64_t elapsedMs = (nowUs - mSysAnchorTime) / 1000;
+    int64_t elapsedRtpTime = (elapsedMs * (mClockRate / 1000));
+    int64_t expectedRtpTime = mFirstRtpTime + elapsedRtpTime;
+
+    int32_t rtpTime;
+    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+    int32_t delayMs = (expectedRtpTime - rtpTime) / (mClockRate / 1000);
+
+    mAvgUnderlineDelayMs = ((mAvgUnderlineDelayMs * 15) + delayMs) / 16;
+}
+
+void ARTPSource::adjustAnchorTimeIfRequired(int64_t nowUs) {
+    if (nowUs - mLastSysAnchorTimeUpdatedUs < 1000000L) {
+        return;
+    }
+
+    if (mAvgUnderlineDelayMs < -30) {
+        // adjust underline delay a quarter of desired delay like step by step.
+        mSysAnchorTime += (int64_t)(mAvgUnderlineDelayMs * 1000 / 4);
+        ALOGD("anchor time updated: original(%lld), anchor(%lld), diffMs(%lld)",
+                (long long)mFirstSysTime, (long long)mSysAnchorTime,
+                (long long)(mFirstSysTime - mSysAnchorTime) / 1000);
+
+        mAvgUnderlineDelayMs = 0;
+        mLastSysAnchorTimeUpdatedUs = nowUs;
+
+        // reset a jitter stastics since an anchor time adjusted.
+        mJitterCalc->init(mFirstRtpTime, mSysAnchorTime, 0, mStaticJbTimeMs * 1000);
+    }
+}
+
+bool ARTPSource::queuePacket(const sp<ABuffer> &buffer) {
+    int64_t nowUs = ALooper::GetNowUs();
+    uint32_t seqNum = (uint32_t)buffer->int32Data();
+    int32_t ssrc = 0, rtpTime = 0;
+
     buffer->meta()->findInt32("ssrc", &ssrc);
+    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+    mLatestRtpTime = rtpTime;
 
     if (mNumBuffersReceived++ == 0 && mFirstSysTime == 0) {
-        uint32_t firstRtpTime;
-        CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&firstRtpTime));
-        mFirstSysTime = ALooper::GetNowUs();
+        mFirstSysTime = nowUs;
+        mSysAnchorTime = nowUs;
+        mLastSysAnchorTimeUpdatedUs = nowUs;
         mHighestSeqNumber = seqNum;
         mBaseSeqNumber = seqNum;
-        mFirstRtpTime = firstRtpTime;
+        mFirstRtpTime = rtpTime;
         mFirstSsrc = ssrc;
         ALOGD("first-rtp arrived: first-rtp-time=%u, sys-time=%lld, seq-num=%u, ssrc=%d",
                 mFirstRtpTime, (long long)mFirstSysTime, mHighestSeqNumber, mFirstSsrc);
         mJitterCalc->init(mFirstRtpTime, mFirstSysTime, 0, mStaticJbTimeMs * 1000);
+        if (mQueue.size() > 0) {
+            ALOGD("clearing buffers which belonged to previous timeline"
+                    " since a base timeline has been changed.");
+            mQueue.clear();
+        }
         mQueue.push_back(buffer);
         return true;
     }
@@ -156,6 +273,10 @@
         return false;
     }
 
+    calcTimeGapRtpRtcp(buffer, nowUs);
+    calcUnderlineDelay(buffer, nowUs);
+    adjustAnchorTimeIfRequired(nowUs);
+
     // Only the lower 16-bit of the sequence numbers are transmitted,
     // derive the high-order bits by choosing the candidate closest
     // to the highest sequence number (extended to 32 bits) received so far.
@@ -340,11 +461,11 @@
 
     uint32_t LSR = 0;
     uint32_t DLSR = 0;
-    if (mLastNTPTime != 0) {
-        LSR = (mLastNTPTime >> 16) & 0xffffffff;
+    if (mLastSrNtpTime != 0) {
+        LSR = (mLastSrNtpTime >> 16) & 0xffffffff;
 
         DLSR = (uint32_t)
-            ((ALooper::GetNowUs() - mLastNTPTimeUpdateUs) * 65536.0 / 1E6);
+            ((ALooper::GetNowUs() - mLastSrUpdateTimeUs) * 65536.0 / 1E6);
     }
 
     data[24] = LSR >> 24;
@@ -543,6 +664,35 @@
     mJitterCalc->putInterArrivalData(timeStamp, arrivalTime);
 }
 
+void ARTPSource::setJbTimer(const sp<AMessage> timer) {
+    mJbTimer = timer;
+}
+
+void ARTPSource::setJbAlarmTime(int64_t nowTimeUs, int64_t alarmAfterUs) {
+    if (mJbTimer == NULL) {
+        return;
+    }
+    int64_t alarmTimeUs = nowTimeUs + alarmAfterUs;
+    bool alarm = false;
+    if (mLastJbAlarmTimeUs <= nowTimeUs) {
+        // no more alarm in pending.
+        mLastJbAlarmTimeUs = nowTimeUs + alarmAfterUs;
+        alarm = true;
+    } else if (mLastJbAlarmTimeUs > alarmTimeUs + 5000L) {
+        // bring an alarm forward more than 5ms.
+        mLastJbAlarmTimeUs = alarmTimeUs;
+        alarm = true;
+    } else {
+        // would not set alarm if it is close with before one.
+    }
+
+    if (alarm) {
+        sp<AMessage> notify = mJbTimer->dup();
+        notify->setObject("source", this);
+        notify->post(alarmAfterUs);
+    }
+}
+
 bool ARTPSource::isNeedToEarlyNotify() {
     uint32_t expected = mHighestSeqNumber - mBaseSeqNumber + 1;
     int32_t intervalExpectedInNow = expected - mPrevExpected;
@@ -553,7 +703,7 @@
     return false;
 }
 
-void ARTPSource::notifyPktInfo(int32_t bitrate, bool isRegular) {
+void ARTPSource::notifyPktInfo(int32_t bitrate, int64_t nowUs, bool isRegular) {
     int32_t payloadType = isRegular ? RTP_QUALITY : RTP_QUALITY_EMC;
 
     sp<AMessage> notify = mNotify->dup();
@@ -567,6 +717,11 @@
     notify->setInt32("prev-expected", mPrevExpected);
     notify->setInt32("num-buf-recv", mNumBuffersReceived);
     notify->setInt32("prev-num-buf-recv", mPrevNumBuffersReceived);
+    notify->setInt32("latest-rtp-time", mLatestRtpTime);
+    notify->setInt64("recv-time-us", nowUs);
+    notify->setInt32("rtp-jitter-time-ms",
+            std::max(getBaseJitterTimeMs(), getStaticJitterTimeMs()));
+    notify->setInt32("rtp-rtcpsr-time-gap-ms", (int32_t)mAvgRtpRtcpGapMs);
     notify->post();
 
     if (isRegular) {
diff --git a/media/libstagefright/rtsp/ARTPSource.h b/media/libstagefright/rtsp/ARTPSource.h
index 0edff23..4984e91 100644
--- a/media/libstagefright/rtsp/ARTPSource.h
+++ b/media/libstagefright/rtsp/ARTPSource.h
@@ -31,7 +31,7 @@
 
 namespace android {
 
-const uint32_t kStaticJitterTimeMs = 50;   // 50ms
+const uint32_t kStaticJitterTimeMs = 100;   // 100ms
 
 struct ABuffer;
 struct AMessage;
@@ -49,6 +49,8 @@
         RTCP_FIRST_PACKET = 101,
         RTP_QUALITY = 102,
         RTP_QUALITY_EMC = 103,
+        RTCP_SR = 200,
+        RTCP_RR = 201,
         RTCP_TSFB = 205,
         RTCP_PSFB = 206,
         RTP_CVO = 300,
@@ -56,6 +58,8 @@
     };
 
     void processRTPPacket(const sp<ABuffer> &buffer);
+    void processRTPPacket();
+    void timeReset();
     void timeUpdate(uint32_t rtpTime, uint64_t ntpTime);
     void byeReceived();
 
@@ -76,19 +80,23 @@
     void setStaticJitterTimeMs(const uint32_t jbTimeMs);
     void putBaseJitterData(uint32_t timeStamp, int64_t arrivalTime);
     void putInterArrivalJitterData(uint32_t timeStamp, int64_t arrivalTime);
+    void setJbTimer(const sp<AMessage> timer);
+    void setJbAlarmTime(int64_t nowTimeUs, int64_t alarmAfterUs);
 
     bool isNeedToEarlyNotify();
-    void notifyPktInfo(int32_t bitrate, bool isRegular);
+    void notifyPktInfo(int32_t bitrate, int64_t nowUs, bool isRegular);
     // FIR needs to be sent by missing packet or broken video image.
     void onIssueFIRByAssembler();
 
     void noticeAbandonBuffer(int cnt=1);
 
-    int32_t mFirstSeqNumber;
     uint32_t mFirstRtpTime;
     int64_t mFirstSysTime;
     int32_t mClockRate;
 
+    int64_t mSysAnchorTime;
+    int64_t mLastSysAnchorTimeUpdatedUs;
+
     int32_t mFirstSsrc;
     int32_t mHighestNackNumber;
 
@@ -103,11 +111,14 @@
     uint32_t mPrevExpectedForRR;
     int32_t mPrevNumBuffersReceivedForRR;
 
+    uint32_t mLatestRtpTime;
+
     List<sp<ABuffer> > mQueue;
     sp<ARTPAssembler> mAssembler;
 
     int32_t mStaticJbTimeMs;
     sp<JitterCalc> mJitterCalc;
+    sp<AMessage> mJbTimer;
 
     typedef struct infoNACK {
         uint16_t seqNum;
@@ -120,8 +131,14 @@
     std::map<uint16_t, infoNACK> mNACKMap;
     int getSeqNumToNACK(List<int>& list, int size);
 
-    uint64_t mLastNTPTime;
-    int64_t mLastNTPTimeUpdateUs;
+    uint32_t mLastSrRtpTime;
+    uint64_t mLastSrNtpTime;
+    int64_t mLastSrUpdateTimeUs;
+
+    bool mIsFirstRtpRtcpGap;
+    double mAvgRtpRtcpGapMs;
+    double mAvgUnderlineDelayMs;
+    int64_t mLastJbAlarmTimeUs;
 
     bool mIssueFIRRequests;
     bool mIssueFIRByAssembler;
@@ -130,6 +147,10 @@
 
     sp<AMessage> mNotify;
 
+    void calcTimeGapRtpRtcp(const sp<ABuffer> &buffer, int64_t nowUs);
+    void calcUnderlineDelay(const sp<ABuffer> &buffer, int64_t nowUs);
+    void adjustAnchorTimeIfRequired(int64_t nowUs);
+
     bool queuePacket(const sp<ABuffer> &buffer);
 
     DISALLOW_EVIL_CONSTRUCTORS(ARTPSource);
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 29e263d..11c7aeb 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -204,8 +204,6 @@
     mRTPTimeBase = 0;
     mNumRTPSent = 0;
     mNumRTPOctetsSent = 0;
-    mLastRTPTime = 0;
-    mLastNTPTime = 0;
 
     mOpponentID = 0;
     mBitrate = 192000;
@@ -216,6 +214,7 @@
     mRTPSockNetwork = 0;
 
     mMode = INVALID;
+    mClockRate = 16000;
 }
 
 status_t ARTPWriter::addSource(const sp<MediaSource> &source) {
@@ -265,15 +264,28 @@
         updateSocketNetwork(sockNetwork);
 
     if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+        // rfc6184: RTP Payload Format for H.264 Video
+        // The clock rate in the "a=rtpmap" line MUST be 90000.
         mMode = H264;
+        mClockRate = 90000;
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+        // rfc7798: RTP Payload Format for High Efficiency Video Coding (HEVC)
+        // The clock rate in the "a=rtpmap" line MUST be 90000.
         mMode = H265;
+        mClockRate = 90000;
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_H263)) {
         mMode = H263;
+        // rfc4629: RTP Payload Format for ITU-T Rec. H.263 Video
+        // The clock rate in the "a=rtpmap" line MUST be 90000.
+        mClockRate = 90000;
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
         mMode = AMR_NB;
+        // rfc4867: RTP Payload Format ... (AMR) and (AMR-WB)
+        // The RTP clock rate in "a=rtpmap" MUST be 8000 for AMR and 16000 for AMR-WB
+        mClockRate = 8000;
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
         mMode = AMR_WB;
+        mClockRate = 16000;
     } else {
         TRESPASS();
     }
@@ -646,19 +658,27 @@
     data[6] = (mSourceID >> 8) & 0xff;
     data[7] = mSourceID & 0xff;
 
-    data[8] = mLastNTPTime >> (64 - 8);
-    data[9] = (mLastNTPTime >> (64 - 16)) & 0xff;
-    data[10] = (mLastNTPTime >> (64 - 24)) & 0xff;
-    data[11] = (mLastNTPTime >> 32) & 0xff;
-    data[12] = (mLastNTPTime >> 24) & 0xff;
-    data[13] = (mLastNTPTime >> 16) & 0xff;
-    data[14] = (mLastNTPTime >> 8) & 0xff;
-    data[15] = mLastNTPTime & 0xff;
+    uint64_t ntpTime = GetNowNTP();
+    data[8] = ntpTime >> (64 - 8);
+    data[9] = (ntpTime >> (64 - 16)) & 0xff;
+    data[10] = (ntpTime >> (64 - 24)) & 0xff;
+    data[11] = (ntpTime >> 32) & 0xff;
+    data[12] = (ntpTime >> 24) & 0xff;
+    data[13] = (ntpTime >> 16) & 0xff;
+    data[14] = (ntpTime >> 8) & 0xff;
+    data[15] = ntpTime & 0xff;
 
-    data[16] = (mLastRTPTime >> 24) & 0xff;
-    data[17] = (mLastRTPTime >> 16) & 0xff;
-    data[18] = (mLastRTPTime >> 8) & 0xff;
-    data[19] = mLastRTPTime & 0xff;
+    // A current rtpTime can be calculated from ALooper::GetNowUs().
+    // This is expecting a timestamp of raw frame from a media source is
+    // on the same time context across components in android media framework
+    // which can be queried by ALooper::GetNowUs().
+    // In other words, ALooper::GetNowUs() is on the same timeline as the time
+    // of kKeyTime in a MediaBufferBase
+    uint32_t rtpTime = getRtpTime(ALooper::GetNowUs());
+    data[16] = (rtpTime >> 24) & 0xff;
+    data[17] = (rtpTime >> 16) & 0xff;
+    data[18] = (rtpTime >> 8) & 0xff;
+    data[19] = rtpTime & 0xff;
 
     data[20] = mNumRTPSent >> 24;
     data[21] = (mNumRTPSent >> 16) & 0xff;
@@ -780,6 +800,13 @@
     return (hi << 32) | lo;
 }
 
+uint32_t ARTPWriter::getRtpTime(int64_t timeUs) {
+    int32_t clockPerMs = mClockRate / 1000;
+    int64_t rtpTime = mRTPTimeBase + (timeUs * clockPerMs / 1000LL);
+
+    return (uint32_t)rtpTime;
+}
+
 void ARTPWriter::dumpSessionDesc() {
     AString sdp;
     sdp = "v=0\r\n";
@@ -981,7 +1008,7 @@
 
     sendVPSSPSPPSIfIFrame(mediaBuf, timeUs);
 
-    uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100ll);
+    uint32_t rtpTime = getRtpTime(timeUs);
 
     CHECK(mediaBuf->range_length() > 0);
     const uint8_t *mediaData =
@@ -1156,9 +1183,6 @@
             offset += size;
         }
     }
-
-    mLastRTPTime = rtpTime;
-    mLastNTPTime = GetNowNTP();
 }
 
 void ARTPWriter::sendAVCData(MediaBufferBase *mediaBuf) {
@@ -1170,7 +1194,7 @@
 
     sendSPSPPSIfIFrame(mediaBuf, timeUs);
 
-    uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100LL);
+    uint32_t rtpTime = getRtpTime(timeUs);
 
     CHECK(mediaBuf->range_length() > 0);
     const uint8_t *mediaData =
@@ -1343,9 +1367,6 @@
             offset += size;
         }
     }
-
-    mLastRTPTime = rtpTime;
-    mLastNTPTime = GetNowNTP();
 }
 
 void ARTPWriter::sendH263Data(MediaBufferBase *mediaBuf) {
@@ -1354,7 +1375,7 @@
     int64_t timeUs;
     CHECK(mediaBuf->meta_data().findInt64(kKeyTime, &timeUs));
 
-    uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100LL);
+    uint32_t rtpTime = getRtpTime(timeUs);
 
     const uint8_t *mediaData =
         (const uint8_t *)mediaBuf->data() + mediaBuf->range_offset();
@@ -1405,9 +1426,6 @@
         ++mNumRTPSent;
         mNumRTPOctetsSent += buffer->size() - 12;
     }
-
-    mLastRTPTime = rtpTime;
-    mLastNTPTime = GetNowNTP();
 }
 
 void ARTPWriter::updateCVODegrees(int32_t cvoDegrees) {
@@ -1490,7 +1508,7 @@
 
     int64_t timeUs;
     CHECK(mediaBuf->meta_data().findInt64(kKeyTime, &timeUs));
-    uint32_t rtpTime = mRTPTimeBase + (timeUs / (isWide ? 250 : 125));
+    uint32_t rtpTime = getRtpTime(timeUs);
 
     // hexdump(mediaData, mediaLength);
 
@@ -1564,9 +1582,6 @@
     ++mSeqNo;
     ++mNumRTPSent;
     mNumRTPOctetsSent += buffer->size() - 12;
-
-    mLastRTPTime = rtpTime;
-    mLastNTPTime = GetNowNTP();
 }
 
 void ARTPWriter::makeSocketPairAndBind(String8& localIp, int localPort,
diff --git a/media/libstagefright/rtsp/ARTPWriter.h b/media/libstagefright/rtsp/ARTPWriter.h
index 28d6ec5..2982cf6 100644
--- a/media/libstagefright/rtsp/ARTPWriter.h
+++ b/media/libstagefright/rtsp/ARTPWriter.h
@@ -108,14 +108,13 @@
     MediaBufferBase *mSPSBuf;
     MediaBufferBase *mPPSBuf;
 
+    uint32_t mClockRate;
     uint32_t mSourceID;
     uint32_t mPayloadType;
     uint32_t mSeqNo;
     uint32_t mRTPTimeBase;
     uint32_t mNumRTPSent;
     uint32_t mNumRTPOctetsSent;
-    uint32_t mLastRTPTime;
-    uint64_t mLastNTPTime;
 
     uint32_t mOpponentID;
     uint32_t mBitrate;
@@ -136,6 +135,7 @@
     } mMode;
 
     static uint64_t GetNowNTP();
+    uint32_t getRtpTime(int64_t timeUs);
 
     void initState();
     void onRead(const sp<AMessage> &msg);
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 0fdf431..988cec7 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -74,7 +74,8 @@
 
 // The allowed maximum number of stale access units at the beginning of
 // a new sequence.
-static int32_t kMaxAllowedStaleAccessUnits = 20;
+static int32_t kMaxAllowedStaleAudioAccessUnits = 20;
+static int32_t kMaxAllowedStaleVideoAccessUnits = 400;
 
 static int64_t kTearDownTimeoutUs = 3000000ll;
 
@@ -108,6 +109,10 @@
     }
 }
 
+static int32_t GetMaxAllowedStaleCount(bool isVideo) {
+    return isVideo ? kMaxAllowedStaleVideoAccessUnits : kMaxAllowedStaleAudioAccessUnits;
+}
+
 struct MyHandler : public AHandler {
     enum {
         kWhatConnected                  = 'conn',
@@ -1330,6 +1335,8 @@
 
                         ALOGV("rtp-info: %s", response->mHeaders.valueAt(i).c_str());
 
+                        mRTPConn->seekStream();
+
                         ALOGI("seek completed.");
                     }
                 }
@@ -1514,7 +1521,7 @@
             TrackInfo *info = &mTracks.editItemAt(trackIndex);
             info->mFirstSeqNumInSegment = seq;
             info->mNewSegment = true;
-            info->mAllowedStaleAccessUnits = kMaxAllowedStaleAccessUnits;
+            info->mAllowedStaleAccessUnits = GetMaxAllowedStaleCount(info->mIsVideo);
 
             CHECK(GetAttribute((*it).c_str(), "rtptime", &val));
 
@@ -1556,6 +1563,7 @@
         int mRTPSocket;
         int mRTCPSocket;
         bool mUsingInterleavedTCP;
+        bool mIsVideo;
         uint32_t mFirstSeqNumInSegment;
         bool mNewSegment;
         int32_t mAllowedStaleAccessUnits;
@@ -1640,9 +1648,10 @@
         info->mURL = trackURL;
         info->mPacketSource = source;
         info->mUsingInterleavedTCP = false;
+        info->mIsVideo = source->isVideo();
         info->mFirstSeqNumInSegment = 0;
         info->mNewSegment = true;
-        info->mAllowedStaleAccessUnits = kMaxAllowedStaleAccessUnits;
+        info->mAllowedStaleAccessUnits = GetMaxAllowedStaleCount(info->mIsVideo);
         info->mRTPSocket = -1;
         info->mRTCPSocket = -1;
         info->mRTPAnchor = 0;
@@ -1838,11 +1847,12 @@
                 // by ARTPSource. Only the low 16 bits of seq in RTP-Info of reply of
                 // RTSP "PLAY" command should be used to detect the first RTP packet
                 // after seeking.
+                int32_t maxAllowedStaleAccessUnits = GetMaxAllowedStaleCount(track->mIsVideo);
                 if (mSeekable) {
                     if (track->mAllowedStaleAccessUnits > 0) {
                         uint32_t seqNum16 = seqNum & 0xffff;
                         uint32_t firstSeqNumInSegment16 = track->mFirstSeqNumInSegment & 0xffff;
-                        if (seqNum16 > firstSeqNumInSegment16 + kMaxAllowedStaleAccessUnits
+                        if (seqNum16 > firstSeqNumInSegment16 + maxAllowedStaleAccessUnits
                                 || seqNum16 < firstSeqNumInSegment16) {
                             // Not the first rtp packet of the stream after seeking, discarding.
                             track->mAllowedStaleAccessUnits--;
@@ -1857,7 +1867,7 @@
                         mNumAccessUnitsReceived = 0;
                         ALOGW_IF(track->mAllowedStaleAccessUnits == 0,
                              "Still no first rtp packet after %d stale ones",
-                             kMaxAllowedStaleAccessUnits);
+                             maxAllowedStaleAccessUnits);
                         track->mAllowedStaleAccessUnits = -1;
                         return UNKNOWN_ERROR;
                     }
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
index 79b192e..e25658f 100644
--- a/media/mediaserver/Android.bp
+++ b/media/mediaserver/Android.bp
@@ -35,7 +35,6 @@
         "android.hardware.media.omx@1.0",
         "libandroidicu",
         "libfmq",
-        "libbase",
         "libbinder",
         "libhidlbase",
         "liblog",
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index dc1b9b8..58e2d2a 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -18,7 +18,6 @@
 #define LOG_TAG "mediaserver"
 //#define LOG_NDEBUG 0
 
-#include <android-base/properties.h>
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
@@ -43,12 +42,6 @@
     ResourceManagerService::instantiate();
     registerExtensions();
     ::android::hardware::configureRpcThreadpool(16, false);
-
-    if (!android::base::GetBoolProperty("ro.config.low_ram", false)) {
-        // Start the media.transcoding service if the device is not low ram
-        // device.
-        android::base::SetProperty("ctl.start", "media.transcoding");
-    }
     ProcessState::self()->startThreadPool();
     IPCThreadState::self()->joinThreadPool();
     ::android::hardware::joinRpcThreadpool();
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 54a6425..65a163f 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -947,6 +947,7 @@
         output.frameCount = input.frameCount;
         output.notificationFrameCount = input.notificationFrameCount;
         output.flags = input.flags;
+        output.streamType = streamType;
 
         track = thread->createTrack_l(client, streamType, localAttr, &output.sampleRate,
                                       input.config.format, input.config.channel_mask,
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 9e099ce..b9cdab8 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -8220,6 +8220,7 @@
 status_t AudioFlinger::RecordThread::shareAudioHistory_l(
         const std::string& sharedAudioPackageName, audio_session_t sharedSessionId,
         int64_t sharedAudioStartMs) {
+
     if ((hasAudioSession_l(sharedSessionId) & ThreadBase::TRACK_SESSION) == 0) {
         return BAD_VALUE;
     }
@@ -8234,18 +8235,21 @@
     // after one wraparound
     // We assume recent wraparounds on mRsmpInRear only given it is unlikely that the requesting
     // app waits several hours after the start time was computed.
-    const int64_t sharedAudioStartFrames = sharedAudioStartMs * mSampleRate / 1000;
+    int64_t sharedAudioStartFrames = sharedAudioStartMs * mSampleRate / 1000;
     const int32_t sharedOffset = audio_utils::safe_sub_overflow(mRsmpInRear,
           (int32_t)sharedAudioStartFrames);
-    if (sharedOffset < 0
-          || sharedOffset > mRsmpInFrames) {
-      return BAD_VALUE;
+    // Bring the start frame position within the input buffer to match the documented
+    // "best effort" behavior of the API.
+    if (sharedOffset < 0) {
+        sharedAudioStartFrames = mRsmpInRear;
+    } else if (sharedOffset > mRsmpInFrames) {
+        sharedAudioStartFrames =
+                audio_utils::safe_sub_overflow(mRsmpInRear, (int32_t)mRsmpInFrames);
     }
 
     mSharedAudioPackageName = sharedAudioPackageName;
     if (mSharedAudioPackageName.empty()) {
-        mSharedAudioSessionId = AUDIO_SESSION_NONE;
-        mSharedAudioStartFrames = -1;
+        resetAudioHistory_l();
     } else {
         mSharedAudioSessionId = sharedSessionId;
         mSharedAudioStartFrames = (int32_t)sharedAudioStartFrames;
@@ -8253,6 +8257,12 @@
     return NO_ERROR;
 }
 
+void AudioFlinger::RecordThread::resetAudioHistory_l() {
+    mSharedAudioSessionId = AUDIO_SESSION_NONE;
+    mSharedAudioStartFrames = -1;
+    mSharedAudioPackageName = "";
+}
+
 void AudioFlinger::RecordThread::updateMetadata_l()
 {
     if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
@@ -8862,23 +8872,22 @@
 int32_t AudioFlinger::RecordThread::getOldestFront_l()
 {
     if (mTracks.size() == 0) {
-        return 0;
+        return mRsmpInRear;
     }
     int32_t oldestFront = mRsmpInRear;
     int32_t maxFilled = 0;
     for (size_t i = 0; i < mTracks.size(); i++) {
         int32_t front = mTracks[i]->mResamplerBufferProvider->getFront();
         int32_t filled;
-        if (front <= mRsmpInRear) {
-            filled = mRsmpInRear - front;
-        } else {
-            filled = (int32_t)((int64_t)mRsmpInRear + UINT32_MAX + 1 - front);
-        }
+        (void)__builtin_sub_overflow(mRsmpInRear, front, &filled);
         if (filled > maxFilled) {
             oldestFront = front;
             maxFilled = filled;
         }
     }
+    if (maxFilled > mRsmpInFrames) {
+        (void)__builtin_sub_overflow(mRsmpInRear, mRsmpInFrames, &oldestFront);
+    }
     return oldestFront;
 }
 
@@ -8928,7 +8937,7 @@
                 "resizeInputBuffer_l() called with shared history and unallocated buffer");
         size_t rsmpInFrames = (size_t)maxSharedAudioHistoryMs * mSampleRate / 1000;
         // never reduce resampler input buffer size
-        if (rsmpInFrames < mRsmpInFrames) {
+        if (rsmpInFrames <= mRsmpInFrames) {
             return;
         }
         mRsmpInFrames = rsmpInFrames;
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index eee1f2b..16082a9 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1789,6 +1789,7 @@
             status_t    shareAudioHistory_l(const std::string& sharedAudioPackageName,
                                           audio_session_t sharedSessionId = AUDIO_SESSION_NONE,
                                           int64_t sharedAudioStartMs = -1);
+            void        resetAudioHistory_l();
 
     virtual bool        isStreamInitialized() {
                             return !(mInput == nullptr || mInput->stream == nullptr);
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index a6e3c06..d2a30b1 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -2458,7 +2458,7 @@
             RecordThread *recordThread = (RecordThread *) thread.get();
             priorState = mState;
             if (!mSharedAudioPackageName.empty()) {
-                recordThread->shareAudioHistory_l("");
+                recordThread->resetAudioHistory_l();
             }
             recordThread->destroyTrack_l(this); // move mState to STOPPED, terminate
         }
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index ca8e96c..c73c17d 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -393,12 +393,14 @@
                 || outputs.isActiveLocally(
                     toVolumeSource(AUDIO_STREAM_ACCESSIBILITY),
                     SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY);
-        // - for STRATEGY_SONIFICATION:
+
+        bool ringActiveLocally = outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_RING), 0);
+        // - for STRATEGY_SONIFICATION and ringtone active:
         // if SPEAKER was selected, and SPEAKER_SAFE is available, use SPEAKER_SAFE instead
         // - for STRATEGY_SONIFICATION_RESPECTFUL:
         // if no media is playing on the device, check for mandatory use of "safe" speaker
         // when media would have played on speaker, and the safe speaker path is available
-        if (strategy == STRATEGY_SONIFICATION
+        if (strategy == STRATEGY_SONIFICATION || ringActiveLocally
             || (strategy == STRATEGY_SONIFICATION_RESPECTFUL && !mediaActiveLocally)) {
             devices.replaceDevicesByType(
                     AUDIO_DEVICE_OUT_SPEAKER,
@@ -506,7 +508,7 @@
         switch (commDeviceType) {
         case AUDIO_DEVICE_OUT_BLE_HEADSET:
             device = availableDevices.getDevice(
-                    AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
+                    AUDIO_DEVICE_IN_BLE_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
             break;
         case AUDIO_DEVICE_OUT_SPEAKER:
             device = availableDevices.getFirstExistingDevice({
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 83a4a37..cc2d8e8 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -5849,12 +5849,11 @@
         // With low-latency playing on speaker, music on WFD, when the first low-latency
         // output is stopped, getNewOutputDevices checks for a product strategy
         // from the list, as STRATEGY_SONIFICATION comes prior to STRATEGY_MEDIA.
-        // If an ALARM, RING or ENFORCED_AUDIBLE stream is supported by the product strategy,
+        // If an ALARM or ENFORCED_AUDIBLE stream is supported by the product strategy,
         // devices are returned for STRATEGY_SONIFICATION without checking whether the
         // stream is associated to the output descriptor.
         if (doGetOutputDevicesForVoice() || outputDesc->isStrategyActive(productStrategy) ||
                ((hasStreamActive(AUDIO_STREAM_ALARM) ||
-                hasStreamActive(AUDIO_STREAM_RING) ||
                 hasStreamActive(AUDIO_STREAM_ENFORCED_AUDIBLE)) &&
                 mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc))) {
             // Retrieval of devices for voice DL is done on primary output profile, cannot
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index b4b6ddf..9987252 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -675,7 +675,7 @@
         sp<AudioRecordClient> client = new AudioRecordClient(attr, input, session, portId,
                                                              selectedDeviceId, adjAttributionSource,
                                                              canCaptureOutput, canCaptureHotword,
-                                                             mAudioCommandThread);
+                                                             mOutputCommandThread);
         mAudioRecordClients.add(portId, client);
     }
 
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index c28c24b..26562e0 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -83,6 +83,7 @@
         "device3/Camera3OutputStreamInterface.cpp",
         "device3/Camera3OutputUtils.cpp",
         "device3/Camera3DeviceInjectionMethods.cpp",
+        "device3/UHRCropAndMeteringRegionMapper.cpp",
         "gui/RingBufferConsumer.cpp",
         "hidl/AidlCameraDeviceCallbacks.cpp",
         "hidl/AidlCameraServiceListener.cpp",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c1d7b55..d0d3a9d 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -237,10 +237,16 @@
         }
     }
 
-    //Derive primary rear/front cameras, and filter their charactierstics.
-    //This needs to be done after all cameras are enumerated and camera ids are sorted.
+    // Derive primary rear/front cameras, and filter their charactierstics.
+    // This needs to be done after all cameras are enumerated and camera ids are sorted.
     if (SessionConfigurationUtils::IS_PERF_CLASS) {
-        filterSPerfClassCharacteristics();
+        // Assume internal cameras are advertised from the same
+        // provider. If multiple providers are registered at different time,
+        // and each provider contains multiple internal color cameras, the current
+        // logic may filter the characteristics of more than one front/rear color
+        // cameras.
+        Mutex::Autolock l(mServiceLock);
+        filterSPerfClassCharacteristicsLocked();
     }
 
     return OK;
@@ -313,7 +319,7 @@
     filterAPI1SystemCameraLocked(mNormalDeviceIds);
 }
 
-void CameraService::filterSPerfClassCharacteristics() {
+void CameraService::filterSPerfClassCharacteristicsLocked() {
     // To claim to be S Performance primary cameras, the cameras must be
     // backward compatible. So performance class primary camera Ids must be API1
     // compatible.
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index aeba7f2..bc2e347 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -948,9 +948,10 @@
     void updateCameraNumAndIds();
 
     /**
-     * Filter camera characteristics for S Performance class primary cameras
+     * Filter camera characteristics for S Performance class primary cameras.
+     * mServiceLock should be locked.
      */
-    void filterSPerfClassCharacteristics();
+    void filterSPerfClassCharacteristicsLocked();
 
     // File descriptor to temp file used for caching previous open
     // session dumpsys info.
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 7045128..4f2b878 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -476,15 +476,16 @@
         const hardware::hidl_string& /*fqName*/,
         const hardware::hidl_string& name,
         bool preexisting) {
+    status_t res = OK;
     std::lock_guard<std::mutex> providerLock(mProviderLifecycleLock);
     {
         std::lock_guard<std::mutex> lock(mInterfaceMutex);
 
-        addProviderLocked(name, preexisting);
+        res = addProviderLocked(name, preexisting);
     }
 
     sp<StatusListener> listener = getStatusListener();
-    if (nullptr != listener.get()) {
+    if (nullptr != listener.get() && res == OK) {
         listener->onNewProviderRegistered();
     }
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 0101c58..fd645c7 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -171,6 +171,13 @@
             mZoomRatioMappers[physicalId] = ZoomRatioMapper(
                     &mPhysicalDeviceInfoMap[physicalId],
                     mSupportNativeZoomRatio, usePrecorrectArray);
+
+            if (SessionConfigurationUtils::isUltraHighResolutionSensor(
+                    mPhysicalDeviceInfoMap[physicalId])) {
+                mUHRCropAndMeteringRegionMappers[physicalId] =
+                        UHRCropAndMeteringRegionMapper(mPhysicalDeviceInfoMap[physicalId],
+                                usePrecorrectArray);
+            }
         }
     }
 
@@ -299,9 +306,25 @@
         sessionParamKeys.insertArrayAt(sessionKeysEntry.data.i32, 0, sessionKeysEntry.count);
     }
 
+    camera_metadata_entry_t availableTestPatternModes = mDeviceInfo.find(
+            ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES);
+    for (size_t i = 0; i < availableTestPatternModes.count; i++) {
+        if (availableTestPatternModes.data.i32[i] ==
+                ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR) {
+            mSupportCameraMute = true;
+            mSupportTestPatternSolidColor = true;
+            break;
+        } else if (availableTestPatternModes.data.i32[i] ==
+                ANDROID_SENSOR_TEST_PATTERN_MODE_BLACK) {
+            mSupportCameraMute = true;
+            mSupportTestPatternSolidColor = false;
+        }
+    }
+
     /** Start up request queue thread */
     mRequestThread = new RequestThread(
-            this, mStatusTracker, mInterface, sessionParamKeys, mUseHalBufManager);
+            this, mStatusTracker, mInterface, sessionParamKeys,
+            mUseHalBufManager, mSupportCameraMute);
     res = mRequestThread->run(String8::format("C3Dev-%s-ReqQueue", mId.string()).string());
     if (res != OK) {
         SET_ERR_L("Unable to start request queue thread: %s (%d)",
@@ -348,23 +371,13 @@
     mZoomRatioMappers[mId.c_str()] = ZoomRatioMapper(&mDeviceInfo,
             mSupportNativeZoomRatio, usePrecorrectArray);
 
-    if (RotateAndCropMapper::isNeeded(&mDeviceInfo)) {
-        mRotateAndCropMappers.emplace(mId.c_str(), &mDeviceInfo);
+    if (SessionConfigurationUtils::isUltraHighResolutionSensor(mDeviceInfo)) {
+        mUHRCropAndMeteringRegionMappers[mId.c_str()] =
+                UHRCropAndMeteringRegionMapper(mDeviceInfo, usePrecorrectArray);
     }
 
-    camera_metadata_entry_t availableTestPatternModes = mDeviceInfo.find(
-            ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES);
-    for (size_t i = 0; i < availableTestPatternModes.count; i++) {
-        if (availableTestPatternModes.data.i32[i] ==
-                ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR) {
-            mSupportCameraMute = true;
-            mSupportTestPatternSolidColor = true;
-            break;
-        } else if (availableTestPatternModes.data.i32[i] ==
-                ANDROID_SENSOR_TEST_PATTERN_MODE_BLACK) {
-            mSupportCameraMute = true;
-            mSupportTestPatternSolidColor = false;
-        }
+    if (RotateAndCropMapper::isNeeded(&mDeviceInfo)) {
+        mRotateAndCropMappers.emplace(mId.c_str(), &mDeviceInfo);
     }
 
     mInjectionMethods = new Camera3DeviceInjectionMethods(this);
@@ -2450,9 +2463,9 @@
 
         auto testPatternDataEntry =
                 newRequest->mSettingsList.begin()->metadata.find(ANDROID_SENSOR_TEST_PATTERN_DATA);
-        if (testPatternDataEntry.count > 0) {
-            memcpy(newRequest->mOriginalTestPatternData, testPatternModeEntry.data.i32,
-                    sizeof(newRequest->mOriginalTestPatternData));
+        if (testPatternDataEntry.count >= 4) {
+            memcpy(newRequest->mOriginalTestPatternData, testPatternDataEntry.data.i32,
+                    sizeof(CaptureRequest::mOriginalTestPatternData));
         } else {
             newRequest->mOriginalTestPatternData[0] = 0;
             newRequest->mOriginalTestPatternData[1] = 0;
@@ -4143,7 +4156,8 @@
 Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent,
         sp<StatusTracker> statusTracker,
         sp<HalInterface> interface, const Vector<int32_t>& sessionParamKeys,
-        bool useHalBufManager) :
+        bool useHalBufManager,
+        bool supportCameraMute) :
         Thread(/*canCallJava*/false),
         mParent(parent),
         mStatusTracker(statusTracker),
@@ -4169,7 +4183,8 @@
         mRequestLatency(kRequestLatencyBinSize),
         mSessionParamKeys(sessionParamKeys),
         mLatestSessionParams(sessionParamKeys.size()),
-        mUseHalBufManager(useHalBufManager) {
+        mUseHalBufManager(useHalBufManager),
+        mSupportCameraMute(supportCameraMute){
     mStatusId = statusTracker->addComponent("RequestThread");
 }
 
@@ -4815,12 +4830,33 @@
             }
 
             {
-                // Correct metadata regions for distortion correction if enabled
                 sp<Camera3Device> parent = mParent.promote();
                 if (parent != nullptr) {
                     List<PhysicalCameraSettings>::iterator it;
                     for (it = captureRequest->mSettingsList.begin();
                             it != captureRequest->mSettingsList.end(); it++) {
+                        if (parent->mUHRCropAndMeteringRegionMappers.find(it->cameraId) ==
+                                parent->mUHRCropAndMeteringRegionMappers.end()) {
+                            continue;
+                        }
+
+                        if (!captureRequest->mUHRCropAndMeteringRegionsUpdated) {
+                            res = parent->mUHRCropAndMeteringRegionMappers[it->cameraId].
+                                    updateCaptureRequest(&(it->metadata));
+                            if (res != OK) {
+                                SET_ERR("RequestThread: Unable to correct capture requests "
+                                        "for scaler crop region and metering regions for request "
+                                        "%d: %s (%d)", halRequest->frame_number, strerror(-res),
+                                        res);
+                                return INVALID_OPERATION;
+                            }
+                            captureRequest->mUHRCropAndMeteringRegionsUpdated = true;
+                        }
+                    }
+
+                    // Correct metadata regions for distortion correction if enabled
+                    for (it = captureRequest->mSettingsList.begin();
+                            it != captureRequest->mSettingsList.end(); it++) {
                         if (parent->mDistortionMappers.find(it->cameraId) ==
                                 parent->mDistortionMappers.end()) {
                             continue;
@@ -5829,6 +5865,8 @@
         const sp<CaptureRequest> &request) {
     ATRACE_CALL();
 
+    if (!mSupportCameraMute) return false;
+
     Mutex::Autolock l(mTriggerMutex);
 
     bool changed = false;
@@ -5864,16 +5902,16 @@
     }
 
     auto testPatternColor = metadata.find(ANDROID_SENSOR_TEST_PATTERN_DATA);
-    if (testPatternColor.count > 0) {
+    if (testPatternColor.count >= 4) {
         for (size_t i = 0; i < 4; i++) {
-            if (testPatternColor.data.i32[i] != (int32_t)testPatternData[i]) {
+            if (testPatternColor.data.i32[i] != testPatternData[i]) {
                 testPatternColor.data.i32[i] = testPatternData[i];
                 changed = true;
             }
         }
     } else {
         metadata.update(ANDROID_SENSOR_TEST_PATTERN_DATA,
-                (int32_t*)testPatternData, 4);
+                testPatternData, 4);
         changed = true;
     }
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 53a696f..39714f0 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -50,6 +50,7 @@
 #include "device3/DistortionMapper.h"
 #include "device3/ZoomRatioMapper.h"
 #include "device3/RotateAndCropMapper.h"
+#include "device3/UHRCropAndMeteringRegionMapper.h"
 #include "device3/InFlightRequest.h"
 #include "device3/Camera3OutputInterface.h"
 #include "device3/Camera3OfflineSession.h"
@@ -589,6 +590,9 @@
         bool                                mRotationAndCropUpdated = false;
         // Whether this capture request's zoom ratio update has been done.
         bool                                mZoomRatioUpdated = false;
+        // Whether this max resolution capture request's  crop / metering region update has been
+        // done.
+        bool                                mUHRCropAndMeteringRegionsUpdated = false;
     };
     typedef List<sp<CaptureRequest> > RequestList;
 
@@ -809,7 +813,8 @@
                 sp<camera3::StatusTracker> statusTracker,
                 sp<HalInterface> interface,
                 const Vector<int32_t>& sessionParamKeys,
-                bool useHalBufManager);
+                bool useHalBufManager,
+                bool supportCameraMute);
         ~RequestThread();
 
         void     setNotificationListener(wp<NotificationListener> listener);
@@ -1082,6 +1087,7 @@
         std::map<int32_t, std::set<String8>> mGroupIdPhysicalCameraMap;
 
         const bool         mUseHalBufManager;
+        const bool         mSupportCameraMute;
     };
     sp<RequestThread> mRequestThread;
 
@@ -1224,6 +1230,12 @@
     std::unordered_map<std::string, camera3::ZoomRatioMapper> mZoomRatioMappers;
 
     /**
+     * UHR request crop / metering region mapper support
+     */
+    std::unordered_map<std::string, camera3::UHRCropAndMeteringRegionMapper>
+            mUHRCropAndMeteringRegionMappers;
+
+    /**
      * RotateAndCrop mapper support
      */
     std::unordered_map<std::string, camera3::RotateAndCropMapper> mRotateAndCropMappers;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index ab861ad..03b77fc 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -657,17 +657,17 @@
         size_t remainingBuffers = (mState == STATE_PREPARING ? mTotalBufferCount :
                                    camera_stream::max_buffers) - mHandoutTotalBufferCount;
         mLock.unlock();
-        std::unique_lock<std::mutex> batchLock(mBatchLock);
 
         nsecs_t dequeueStart = systemTime(SYSTEM_TIME_MONOTONIC);
 
-        if (mBatchSize == 1) {
+        size_t batchSize = mBatchSize.load();
+        if (batchSize == 1) {
             sp<ANativeWindow> anw = consumer;
             res = anw->dequeueBuffer(anw.get(), anb, fenceFd);
         } else {
+            std::unique_lock<std::mutex> batchLock(mBatchLock);
             res = OK;
             if (mBatchedBuffers.size() == 0) {
-                size_t batchSize = mBatchSize;
                 if (remainingBuffers == 0) {
                     ALOGE("%s: cannot get buffer while all buffers are handed out", __FUNCTION__);
                     return INVALID_OPERATION;
@@ -675,13 +675,17 @@
                 if (batchSize > remainingBuffers) {
                     batchSize = remainingBuffers;
                 }
+                batchLock.unlock();
                 // Refill batched buffers
-                mBatchedBuffers.resize(batchSize);
-                res = consumer->dequeueBuffers(&mBatchedBuffers);
+                std::vector<Surface::BatchBuffer> batchedBuffers;
+                batchedBuffers.resize(batchSize);
+                res = consumer->dequeueBuffers(&batchedBuffers);
+                batchLock.lock();
                 if (res != OK) {
                     ALOGE("%s: batch dequeueBuffers call failed! %s (%d)",
                             __FUNCTION__, strerror(-res), res);
-                    mBatchedBuffers.clear();
+                } else {
+                    mBatchedBuffers = std::move(batchedBuffers);
                 }
             }
 
@@ -692,7 +696,6 @@
                 mBatchedBuffers.pop_back();
             }
         }
-        batchLock.unlock();
 
         nsecs_t dequeueEnd = systemTime(SYSTEM_TIME_MONOTONIC);
         mDequeueBufferLatency.add(dequeueStart, dequeueEnd);
@@ -1129,7 +1132,6 @@
 
 status_t Camera3OutputStream::setBatchSize(size_t batchSize) {
     Mutex::Autolock l(mLock);
-    std::lock_guard<std::mutex> lock(mBatchLock);
     if (batchSize == 0) {
         ALOGE("%s: invalid batch size 0", __FUNCTION__);
         return BAD_VALUE;
@@ -1145,31 +1147,36 @@
         return INVALID_OPERATION;
     }
 
-    if (batchSize != mBatchSize) {
-        if (mBatchedBuffers.size() != 0) {
-            ALOGE("%s: change batch size from %zu to %zu dynamically is not supported",
-                    __FUNCTION__, mBatchSize, batchSize);
-            return INVALID_OPERATION;
-        }
-
-        if (camera_stream::max_buffers < batchSize) {
-            ALOGW("%s: batch size is capped by max_buffers %d", __FUNCTION__,
-                    camera_stream::max_buffers);
-            batchSize = camera_stream::max_buffers;
-        }
-        mBatchSize = batchSize;
+    if (camera_stream::max_buffers < batchSize) {
+        ALOGW("%s: batch size is capped by max_buffers %d", __FUNCTION__,
+                camera_stream::max_buffers);
+        batchSize = camera_stream::max_buffers;
     }
+
+    size_t defaultBatchSize = 1;
+    if (!mBatchSize.compare_exchange_strong(defaultBatchSize, batchSize)) {
+        ALOGE("%s: change batch size from %zu to %zu dynamically is not supported",
+                __FUNCTION__, defaultBatchSize, batchSize);
+        return INVALID_OPERATION;
+    }
+
     return OK;
 }
 
 void Camera3OutputStream::returnPrefetchedBuffersLocked() {
-    std::lock_guard<std::mutex> batchLock(mBatchLock);
-    if (mBatchedBuffers.size() != 0) {
-        ALOGW("%s: %zu extra prefetched buffers detected. Returning",
-                __FUNCTION__, mBatchedBuffers.size());
+    std::vector<Surface::BatchBuffer> batchedBuffers;
 
-        mConsumer->cancelBuffers(mBatchedBuffers);
-        mBatchedBuffers.clear();
+    {
+        std::lock_guard<std::mutex> batchLock(mBatchLock);
+        if (mBatchedBuffers.size() != 0) {
+            ALOGW("%s: %zu extra prefetched buffers detected. Returning",
+                   __FUNCTION__, mBatchedBuffers.size());
+            batchedBuffers = std::move(mBatchedBuffers);
+        }
+    }
+
+    if (batchedBuffers.size() > 0) {
+        mConsumer->cancelBuffers(batchedBuffers);
     }
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 00e4854..ad03b53 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -312,15 +312,14 @@
     bool mDropBuffers;
 
 
-    // Protecting batch states below, must be acquired after mLock
-    std::mutex mBatchLock;
 
     // The batch size for buffer operation
-    size_t mBatchSize = 1;
+    std::atomic_size_t mBatchSize = 1;
 
+    // Protecting batch states below, must be acquired after mLock
+    std::mutex mBatchLock;
     // Prefetched buffers (ready to be handed to client)
     std::vector<Surface::BatchBuffer> mBatchedBuffers;
-
     // ---- End of mBatchLock protected scope ----
 
     /**
diff --git a/services/camera/libcameraservice/device3/UHRCropAndMeteringRegionMapper.cpp b/services/camera/libcameraservice/device3/UHRCropAndMeteringRegionMapper.cpp
new file mode 100644
index 0000000..c558d91
--- /dev/null
+++ b/services/camera/libcameraservice/device3/UHRCropAndMeteringRegionMapper.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#define LOG_TAG "Camera3-UHRCropAndMeteringRegionMapper"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <algorithm>
+#include <cmath>
+
+#include "device3/UHRCropAndMeteringRegionMapper.h"
+#include "utils/SessionConfigurationUtils.h"
+
+namespace android {
+
+namespace camera3 {
+// For Capture request
+// metering region -> {fwk private key for metering region set, true}
+static std::unordered_map<uint32_t, std::pair<uint32_t, uint32_t>> kMeteringRegionsToCorrect = {
+    {ANDROID_CONTROL_AF_REGIONS,
+        {ANDROID_CONTROL_AF_REGIONS_SET, ANDROID_CONTROL_AF_REGIONS_SET_TRUE}},
+    {ANDROID_CONTROL_AE_REGIONS,
+        {ANDROID_CONTROL_AE_REGIONS_SET, ANDROID_CONTROL_AE_REGIONS_SET_TRUE}},
+    {ANDROID_CONTROL_AWB_REGIONS,
+        {ANDROID_CONTROL_AWB_REGIONS_SET,  ANDROID_CONTROL_AWB_REGIONS_SET_TRUE}}
+};
+
+UHRCropAndMeteringRegionMapper::UHRCropAndMeteringRegionMapper(const CameraMetadata &deviceInfo,
+        bool usePreCorrectedArray) {
+
+    if (usePreCorrectedArray) {
+        if (!SessionConfigurationUtils::getArrayWidthAndHeight(&deviceInfo,
+                ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, &mArrayWidth,
+                &mArrayHeight)) {
+            ALOGE("%s: Couldn't get pre correction active array size", __FUNCTION__);
+            return;
+        }
+        if (!SessionConfigurationUtils::getArrayWidthAndHeight(&deviceInfo,
+                ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
+                &mArrayWidthMaximumResolution, &mArrayHeightMaximumResolution)) {
+            ALOGE("%s: Couldn't get maximum resolution pre correction active array size",
+                    __FUNCTION__);
+            return;
+        }
+    } else {
+        if (!SessionConfigurationUtils::getArrayWidthAndHeight(&deviceInfo,
+                ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, &mArrayWidth,
+                &mArrayHeight)) {
+            ALOGE("%s: Couldn't get active array size", __FUNCTION__);
+            return;
+        }
+        if (!SessionConfigurationUtils::getArrayWidthAndHeight(&deviceInfo,
+                ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
+                &mArrayWidthMaximumResolution, &mArrayHeightMaximumResolution)) {
+            ALOGE("%s: Couldn't get maximum resolution active array size", __FUNCTION__);
+            return;
+        }
+
+    }
+
+    mIsValid = true;
+
+    ALOGV("%s: array size: %d x %d, full res array size: %d x %d,",
+            __FUNCTION__, mArrayWidth, mArrayHeight, mArrayWidthMaximumResolution,
+            mArrayHeightMaximumResolution);
+}
+
+void UHRCropAndMeteringRegionMapper::fixMeteringRegionsIfNeeded(CameraMetadata *request) {
+    if (request == nullptr) {
+      ALOGE("%s request is nullptr, can't fix crop region", __FUNCTION__);
+      return;
+    }
+    for (const auto &entry : kMeteringRegionsToCorrect) {
+        // Check if the metering region Set key is set to TRUE, we don't
+        // need to correct the metering regions.
+        camera_metadata_entry meteringRegionsSetEntry =
+                request->find(entry.second.first);
+        if (meteringRegionsSetEntry.count == 1 &&
+                meteringRegionsSetEntry.data.u8[0] == entry.second.second) {
+            // metering region set by client, doesn't need to be fixed.
+            continue;
+        }
+        camera_metadata_entry meteringRegionEntry = request->find(entry.first);
+        if (meteringRegionEntry.count % 5 != 0) {
+            ALOGE("%s: Metering region entry for tag %d does not have a valid number of entries, "
+                    "skipping", __FUNCTION__, (int)entry.first);
+            continue;
+        }
+        for (size_t j = 0; j < meteringRegionEntry.count; j += 5) {
+            int32_t *meteringRegionStart = meteringRegionEntry.data.i32 + j;
+            meteringRegionStart[0] = 0;
+            meteringRegionStart[1] = 0;
+            meteringRegionStart[2] = mArrayWidthMaximumResolution;
+            meteringRegionStart[3] = mArrayHeightMaximumResolution;
+        }
+    }
+}
+
+void UHRCropAndMeteringRegionMapper::fixCropRegionsIfNeeded(CameraMetadata *request) {
+    if (request == nullptr) {
+      ALOGE("%s request is nullptr, can't fix crop region", __FUNCTION__);
+      return;
+    }
+    // Check if the scalerCropRegionSet key is set to TRUE, we don't
+    // need to correct the crop region.
+    camera_metadata_entry cropRegionSetEntry =
+            request->find(ANDROID_SCALER_CROP_REGION_SET);
+    if (cropRegionSetEntry.count == 1 &&
+        cropRegionSetEntry.data.u8[0] == ANDROID_SCALER_CROP_REGION_SET_TRUE) {
+        // crop regions set by client, doesn't need to be fixed.
+        return;
+    }
+    camera_metadata_entry_t cropRegionEntry = request->find(ANDROID_SCALER_CROP_REGION);
+    if (cropRegionEntry.count == 4) {
+        cropRegionEntry.data.i32[0] = 0;
+        cropRegionEntry.data.i32[1] = 0;
+        cropRegionEntry.data.i32[2] = mArrayWidthMaximumResolution;
+        cropRegionEntry.data.i32[3] = mArrayHeightMaximumResolution;
+    }
+}
+
+status_t UHRCropAndMeteringRegionMapper::updateCaptureRequest(CameraMetadata* request) {
+    if (request == nullptr) {
+        ALOGE("%s Invalid request, request is nullptr", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    if (!mIsValid) {
+        ALOGE("%s UHRCropAndMeteringRegionMapper didn't initialize correctly", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    camera_metadata_entry sensorPixelModeEntry = request->find(ANDROID_SENSOR_PIXEL_MODE);
+
+    // Check if this is max resolution capture, if not, we don't need to do
+    // anything.
+    if (sensorPixelModeEntry.count != 0) {
+        int32_t sensorPixelMode = sensorPixelModeEntry.data.u8[0];
+        if (sensorPixelMode != ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) {
+            // Correction not needed for default mode requests.
+           return OK;
+        }
+    } else {
+        // sensor pixel mode not set -> default sensor pixel mode request, which
+        // doesn't need correction.
+        return OK;
+    }
+
+    fixCropRegionsIfNeeded(request);
+    fixMeteringRegionsIfNeeded(request);
+    return OK;
+}
+
+} // namespace camera3
+
+} // namespace android
diff --git a/services/camera/libcameraservice/device3/UHRCropAndMeteringRegionMapper.h b/services/camera/libcameraservice/device3/UHRCropAndMeteringRegionMapper.h
new file mode 100644
index 0000000..a026e6d
--- /dev/null
+++ b/services/camera/libcameraservice/device3/UHRCropAndMeteringRegionMapper.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 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 ANDROID_SERVERS_UHRCROP_REGIONS_MAPPER_H
+#define ANDROID_SERVERS_UHRCROP_REGIONS_MAPPER_H
+
+#include <utils/Errors.h>
+#include <array>
+
+#include "camera/CameraMetadata.h"
+
+namespace android {
+
+namespace camera3 {
+
+/**
+ * Utilities to transform SCALER_CROP_REGION and metering regions for ultra high
+ * resolution sensors.
+ */
+class UHRCropAndMeteringRegionMapper {
+ public:
+    UHRCropAndMeteringRegionMapper() = default;
+    UHRCropAndMeteringRegionMapper(const CameraMetadata &deviceInfo, bool usePreCorrectionArray);
+
+    /**
+     * Adjust capture request assuming rotate and crop AUTO is enabled
+     */
+    status_t updateCaptureRequest(CameraMetadata *request);
+
+ private:
+
+    void fixCropRegionsIfNeeded(CameraMetadata *request);
+    void fixMeteringRegionsIfNeeded(CameraMetadata *request);
+
+    int32_t mArrayWidth = 0;
+    int32_t mArrayHeight = 0;
+    int32_t mArrayWidthMaximumResolution = 0;
+    int32_t mArrayHeightMaximumResolution = 0;
+    bool mIsValid = false;
+}; // class UHRCropAndMeteringRegionMapper
+
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
index 1a39510..7ec0956 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
@@ -129,20 +129,6 @@
     return OK;
 }
 
-static bool getArrayWidthAndHeight(const CameraMetadata *deviceInfo,
-        int32_t arrayTag, int32_t *width, int32_t *height) {
-    if (width == nullptr || height == nullptr) {
-        ALOGE("%s: width / height nullptr", __FUNCTION__);
-        return false;
-    }
-    camera_metadata_ro_entry_t entry;
-    entry = deviceInfo->find(arrayTag);
-    if (entry.count != 4) return false;
-    *width = entry.data.i32[2];
-    *height = entry.data.i32[3];
-    return true;
-}
-
 ZoomRatioMapper::ZoomRatioMapper(const CameraMetadata* deviceInfo,
         bool supportNativeZoomRatio, bool usePrecorrectArray) {
     initRemappedKeys();
@@ -156,13 +142,13 @@
     int32_t activeMaximumResolutionW = 0;
     int32_t activeMaximumResolutionH = 0;
 
-    if (!getArrayWidthAndHeight(deviceInfo, ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
-            &arrayW, &arrayH)) {
+    if (!SessionConfigurationUtils::getArrayWidthAndHeight(deviceInfo,
+            ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, &arrayW, &arrayH)) {
         ALOGE("%s: Couldn't get pre correction active array size", __FUNCTION__);
         return;
     }
-     if (!getArrayWidthAndHeight(deviceInfo, ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
-            &activeW, &activeH)) {
+     if (!SessionConfigurationUtils::getArrayWidthAndHeight(deviceInfo,
+            ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, &activeW, &activeH)) {
         ALOGE("%s: Couldn't get active array size", __FUNCTION__);
         return;
     }
@@ -170,14 +156,14 @@
     bool isUltraHighResolutionSensor =
             camera3::SessionConfigurationUtils::isUltraHighResolutionSensor(*deviceInfo);
     if (isUltraHighResolutionSensor) {
-        if (!getArrayWidthAndHeight(deviceInfo,
+        if (!SessionConfigurationUtils::getArrayWidthAndHeight(deviceInfo,
                 ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
                 &arrayMaximumResolutionW, &arrayMaximumResolutionH)) {
             ALOGE("%s: Couldn't get maximum resolution pre correction active array size",
                     __FUNCTION__);
             return;
         }
-         if (!getArrayWidthAndHeight(deviceInfo,
+         if (!SessionConfigurationUtils::getArrayWidthAndHeight(deviceInfo,
                 ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
                 &activeMaximumResolutionW, &activeMaximumResolutionH)) {
             ALOGE("%s: Couldn't get maximum resolution pre correction active array size",
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index 454c05f..a239c81 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -142,19 +142,19 @@
         case ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS:
             return ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
         case ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS:
-            return ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS;
+            return ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION;
         case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS:
             return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
         case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS:
             return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
         case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS:
-            return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS;
+            return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION;
         case ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS:
             return ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
         case ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS:
             return ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
         case ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS:
-            return ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS;
+            return ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS_MAXIMUM_RESOLUTION;
         case ANDROID_SENSOR_OPAQUE_RAW_SIZE:
             return ANDROID_SENSOR_OPAQUE_RAW_SIZE_MAXIMUM_RESOLUTION;
         case ANDROID_LENS_INTRINSIC_CALIBRATION:
@@ -169,6 +169,19 @@
     return -1;
 }
 
+bool SessionConfigurationUtils::getArrayWidthAndHeight(const CameraMetadata *deviceInfo,
+        int32_t arrayTag, int32_t *width, int32_t *height) {
+    if (width == nullptr || height == nullptr) {
+        ALOGE("%s: width / height nullptr", __FUNCTION__);
+        return false;
+    }
+    camera_metadata_ro_entry_t entry;
+    entry = deviceInfo->find(arrayTag);
+    if (entry.count != 4) return false;
+    *width = entry.data.i32[2];
+    *height = entry.data.i32[3];
+    return true;
+}
 
 StreamConfigurationPair
 SessionConfigurationUtils::getStreamConfigurationPair(const CameraMetadata &staticInfo) {
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index 1fbaa69..192e241 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -85,6 +85,9 @@
             android_dataspace dataSpace, const CameraMetadata& info, bool maxResolution,
             /*out*/int32_t* outWidth, /*out*/int32_t* outHeight);
 
+    static bool getArrayWidthAndHeight(const CameraMetadata *deviceInfo, int32_t arrayTag,
+            int32_t *width, int32_t *height);
+
     //check if format is not custom format
     static bool isPublicFormat(int32_t format);
 
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 0d453cf..5fbcadb 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -126,9 +126,9 @@
     // Prevent this object from getting deleted before the thread has a chance to create
     // its strong pointer. Assume the thread will call decStrong().
     this->incStrong(nullptr);
-    aaudio_result_t result = getStreamInternal()->createThread_l(periodNanos,
-                                                                 aaudio_endpoint_thread_proc,
-                                                                 this);
+    aaudio_result_t result = getStreamInternal()->createThread(periodNanos,
+                                                               aaudio_endpoint_thread_proc,
+                                                               this);
     if (result != AAUDIO_OK) {
         this->decStrong(nullptr); // Because the thread won't do it.
     }