Merge "SoftVorbis: handle flush as well as flush with CSD"
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 97cf6bf..838dd4a 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -30,3 +30,42 @@
     srcs: ["include/camera/**/*.h"],
     license: "NOTICE",
 }
+
+cc_library_shared {
+    name: "libcamera2",
+    srcs: [
+        "NdkCameraManager.cpp",
+        "NdkCameraMetadata.cpp",
+        "NdkCameraDevice.cpp",
+        "NdkCaptureRequest.cpp",
+        "NdkCameraCaptureSession.cpp",
+        "impl/ACameraManager.cpp",
+        "impl/ACameraMetadata.cpp",
+        "impl/ACameraDevice.cpp",
+        "impl/ACameraCaptureSession.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libgui",
+        "libutils",
+        "libandroid_runtime",
+        "libcamera_client",
+        "libstagefright_foundation",
+        "libcutils",
+        "libcamera_metadata",
+        "libmediandk",
+        "libnativewindow",
+    ],
+    cflags: [
+        "-fvisibility=hidden",
+        "-DEXPORT=__attribute__ ((visibility (\"default\")))",
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    export_include_dirs: ["include"],
+    export_shared_lib_headers: [
+        "libnativewindow",
+    ]
+}
diff --git a/camera/ndk/Android.mk b/camera/ndk/Android.mk
index f5ff69d..a5aab07 100644
--- a/camera/ndk/Android.mk
+++ b/camera/ndk/Android.mk
@@ -14,6 +14,8 @@
 # limitations under the License.
 #
 
+# TODO(b/118434782): Remove this file and change name of the libcamera2
+# module in the existing Android.bp file to libcamera2ndk.
 LOCAL_PATH:= $(call my-dir)
 
 ifneq ($(TARGET_BUILD_PDK), true)
diff --git a/include/soundtrigger/ISoundTrigger.h b/include/soundtrigger/ISoundTrigger.h
index 5fd8eb2..ea1aea6 100644
--- a/include/soundtrigger/ISoundTrigger.h
+++ b/include/soundtrigger/ISoundTrigger.h
@@ -40,6 +40,8 @@
     virtual status_t startRecognition(sound_model_handle_t handle,
                                       const sp<IMemory>& dataMemory) = 0;
     virtual status_t stopRecognition(sound_model_handle_t handle) = 0;
+    virtual status_t getModelState(sound_model_handle_t handle,
+                                   sp<IMemory>& eventMemory) = 0;
 
 };
 
diff --git a/include/soundtrigger/SoundTrigger.h b/include/soundtrigger/SoundTrigger.h
index 7a29e31..dcf9ce8 100644
--- a/include/soundtrigger/SoundTrigger.h
+++ b/include/soundtrigger/SoundTrigger.h
@@ -52,6 +52,7 @@
 
             status_t startRecognition(sound_model_handle_t handle, const sp<IMemory>& dataMemory);
             status_t stopRecognition(sound_model_handle_t handle);
+            status_t getModelState(sound_model_handle_t handle, sp<IMemory>& eventMemory);
 
             // BpSoundTriggerClient
             virtual void onRecognitionEvent(const sp<IMemory>& eventMemory);
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index eec0392..3a58aa6 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -150,6 +150,8 @@
     status_t parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size);
     status_t parseClearEncryptedSizes(off64_t offset, bool isSubsampleEncryption, uint32_t flags);
     status_t parseSampleEncryption(off64_t offset);
+    // returns -1 for invalid layer ID
+    int32_t parseHEVCLayerId(const uint8_t *data, size_t size);
 
     struct TrackFragmentHeaderInfo {
         enum Flags {
@@ -4935,6 +4937,35 @@
     return 0;
 }
 
+int32_t MPEG4Source::parseHEVCLayerId(const uint8_t *data, size_t size) {
+    CHECK(data != nullptr && size >= (mNALLengthSize + 2));
+
+    // HEVC NAL-header (16-bit)
+    //  1   6      6     3
+    // |-|uuuuuu|------|iii|
+    //      ^            ^
+    //  NAL_type        layer_id + 1
+    //
+    // Layer-id is non-zero only for Temporal Sub-layer Access pictures (TSA)
+    enum {
+        TSA_N = 2,
+        TSA_R = 3,
+        STSA_N = 4,
+        STSA_R = 5,
+    };
+
+    data += mNALLengthSize;
+    uint16_t nalHeader = data[0] << 8 | data[1];
+
+    uint16_t nalType = (nalHeader >> 9) & 0x3Fu;
+    if (nalType == TSA_N || nalType == TSA_R || nalType == STSA_N || nalType == STSA_R) {
+        int32_t layerIdPlusOne = nalHeader & 0x7u;
+        ALOGD_IF(layerIdPlusOne == 0, "got layerId 0 for TSA picture");
+        return layerIdPlusOne - 1;
+    }
+    return 0;
+}
+
 status_t MPEG4Source::read(
         MediaBufferBase **out, const ReadOptions *options) {
     Mutex::Autolock autoLock(mLock);
@@ -5368,6 +5399,12 @@
             uint32_t layerId = FindAVCLayerId(
                     (const uint8_t *)mBuffer->data(), mBuffer->range_length());
             mBuffer->meta_data().setInt32(kKeyTemporalLayerId, layerId);
+        } else if (mIsHEVC) {
+            int32_t layerId = parseHEVCLayerId(
+                    (const uint8_t *)mBuffer->data(), mBuffer->range_length());
+            if (layerId >= 0) {
+                mBuffer->meta_data().setInt32(kKeyTemporalLayerId, layerId);
+            }
         }
 
         if (isSyncSample) {
@@ -5566,6 +5603,12 @@
                 uint32_t layerId = FindAVCLayerId(
                         (const uint8_t *)mBuffer->data(), mBuffer->range_length());
                 mBuffer->meta_data().setInt32(kKeyTemporalLayerId, layerId);
+            } else if (mIsHEVC) {
+                int32_t layerId = parseHEVCLayerId(
+                        (const uint8_t *)mBuffer->data(), mBuffer->range_length());
+                if (layerId >= 0) {
+                    mBuffer->meta_data().setInt32(kKeyTemporalLayerId, layerId);
+                }
             }
 
             if (isSyncSample) {
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 2ae9b5a..a52ccb1 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -987,11 +987,10 @@
     AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_0, data, size);
     AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, kOpusSampleRate);
     AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mChannelCount);
-    // are these actually used anywhere?
-    // (they are kKeyOpusSeekPreRoll and kKeyOpusCodecDelay respectively)
-    AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_CSD_2, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
-    AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_CSD_1,
-            mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate);
+    int64_t codecdelay = mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate;
+    AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_1, &codecdelay, sizeof(codecdelay));
+    int64_t preroll = kOpusSeekPreRollUs * 1000 /* = 80 ms*/;
+    AMediaFormat_setBuffer(mMeta, AMEDIAFORMAT_KEY_CSD_2, &preroll, sizeof(preroll));
 
     return AMEDIA_OK;
 }
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index c86d4ce..8b35a85 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -399,9 +399,10 @@
         }
         break;
     case TRANSFER_CALLBACK:
+    case TRANSFER_SYNC_NOTIF_CALLBACK:
         if (cbf == NULL || sharedBuffer != 0) {
-            ALOGE("%s(): Transfer type TRANSFER_CALLBACK but cbf == NULL || sharedBuffer != 0",
-                    __func__);
+            ALOGE("%s(): Transfer type %s but cbf == NULL || sharedBuffer != 0",
+                    convertTransferToText(transferType), __func__);
             status = BAD_VALUE;
             goto exit;
         }
@@ -1406,6 +1407,7 @@
         MEDIA_CASE_ENUM(TRANSFER_OBTAIN);
         MEDIA_CASE_ENUM(TRANSFER_SYNC);
         MEDIA_CASE_ENUM(TRANSFER_SHARED);
+        MEDIA_CASE_ENUM(TRANSFER_SYNC_NOTIF_CALLBACK);
         default:
             return "UNRECOGNIZED";
     }
@@ -1438,7 +1440,8 @@
             // use case 3: obtain/release mode
             (mTransfer == TRANSFER_OBTAIN) ||
             // use case 4: synchronous write
-            ((mTransfer == TRANSFER_SYNC) && mThreadCanCallJava);
+            ((mTransfer == TRANSFER_SYNC || mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK)
+                    && mThreadCanCallJava);
 
         bool fastAllowed = sharedBuffer || transferAllowed;
         if (!fastAllowed) {
@@ -1795,7 +1798,7 @@
 
 ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)
 {
-    if (mTransfer != TRANSFER_SYNC) {
+    if (mTransfer != TRANSFER_SYNC && mTransfer != TRANSFER_SYNC_NOTIF_CALLBACK) {
         return INVALID_OPERATION;
     }
 
@@ -1846,7 +1849,17 @@
 
     if (written > 0) {
         mFramesWritten += written / mFrameSize;
+
+        if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
+            const sp<AudioTrackThread> t = mAudioTrackThread;
+            if (t != 0) {
+                // causes wake up of the playback thread, that will callback the client for
+                // more data (with EVENT_CAN_WRITE_MORE_DATA) in processAudioBuffer()
+                t->wake();
+            }
+        }
     }
+
     return written;
 }
 
@@ -2100,8 +2113,8 @@
         if (ns < 0) ns = 0;
     }
 
-    // If not supplying data by EVENT_MORE_DATA, then we're done
-    if (mTransfer != TRANSFER_CALLBACK) {
+    // If not supplying data by EVENT_MORE_DATA or EVENT_CAN_WRITE_MORE_DATA, then we're done
+    if (mTransfer != TRANSFER_CALLBACK && mTransfer != TRANSFER_SYNC_NOTIF_CALLBACK) {
         return ns;
     }
 
@@ -2163,7 +2176,13 @@
         }
 
         size_t reqSize = audioBuffer.size;
-        mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
+        if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
+            // when notifying client it can write more data, pass the total size that can be
+            // written in the next write() call, since it's not passed through the callback
+            audioBuffer.size += nonContig;
+        }
+        mCbf(mTransfer == TRANSFER_CALLBACK ? EVENT_MORE_DATA : EVENT_CAN_WRITE_MORE_DATA,
+                mUserData, &audioBuffer);
         size_t writtenSize = audioBuffer.size;
 
         // Sanity check on returned size
@@ -2174,6 +2193,14 @@
         }
 
         if (writtenSize == 0) {
+            if (mTransfer == TRANSFER_SYNC_NOTIF_CALLBACK) {
+                // The callback EVENT_CAN_WRITE_MORE_DATA was processed in the JNI of
+                // android.media.AudioTrack. The JNI is not using the callback to provide data,
+                // it only signals to the Java client that it can provide more data, which
+                // this track is read to accept now.
+                // The playback thread will be awaken at the next ::write()
+                return NS_WHENEVER;
+            }
             // The callback is done filling buffers
             // Keep this thread going to handle timed events and
             // still try to get more data in intervals of WAIT_PERIOD_MS
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index c5105af..4b84fd1 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -74,6 +74,8 @@
                                     // in the mapping from frame position to presentation time.
                                     // See AudioTimestamp for the information included with event.
 #endif
+        EVENT_CAN_WRITE_MORE_DATA = 9,// Notification that more data can be given by write()
+                                    // This event only occurs for TRANSFER_SYNC_NOTIF_CALLBACK.
     };
 
     /* Client should declare a Buffer and pass the address to obtainBuffer()
@@ -153,6 +155,7 @@
         TRANSFER_OBTAIN,    // call obtainBuffer() and releaseBuffer()
         TRANSFER_SYNC,      // synchronous write()
         TRANSFER_SHARED,    // shared memory
+        TRANSFER_SYNC_NOTIF_CALLBACK, // synchronous write(), notif EVENT_CAN_WRITE_MORE_DATA
     };
 
     /* Constructs an uninitialized AudioTrack. No connection with
@@ -295,6 +298,8 @@
      * Parameters not listed in the AudioTrack constructors above:
      *
      * threadCanCallJava:  Whether callbacks are made from an attached thread and thus can call JNI.
+     *      Only set to true when AudioTrack object is used for a java android.media.AudioTrack
+     *      in its JNI code.
      *
      * Internal state post condition:
      *      (mStreamType == AUDIO_STREAM_DEFAULT) implies this AudioTrack has valid attributes
diff --git a/media/libmedia/include/media/DataSourceDesc.h b/media/libmedia/include/media/DataSourceDesc.h
index c190261..4336767 100644
--- a/media/libmedia/include/media/DataSourceDesc.h
+++ b/media/libmedia/include/media/DataSourceDesc.h
@@ -30,6 +30,11 @@
 // A binder interface for implementing a stagefright DataSource remotely.
 struct DataSourceDesc : public RefBase {
 public:
+    // intentionally less than INT64_MAX
+    // keep consistent with JAVA code
+    static const int64_t kMaxTimeMs = 0x7ffffffffffffffll / 1000;
+    static const int64_t kMaxTimeUs = kMaxTimeMs * 1000;
+
     enum {
         /* No data source has been set yet */
         TYPE_NONE     = 0,
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index cdef637..1e5fa07 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -68,6 +68,9 @@
     METADATA_KEY_VIDEO_FRAME_COUNT  = 32,
     METADATA_KEY_EXIF_OFFSET     = 33,
     METADATA_KEY_EXIF_LENGTH     = 34,
+    METADATA_KEY_COLOR_STANDARD  = 35,
+    METADATA_KEY_COLOR_TRANSFER  = 36,
+    METADATA_KEY_COLOR_RANGE     = 37,
 
     // Add more here...
 };
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index 3b155c5..480a630 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -404,12 +404,12 @@
         return BAD_VALUE;
     }
     // Microsecond is used in NuPlayer2.
-    if (dsd->mStartPositionMs > INT64_MAX / 1000) {
-        dsd->mStartPositionMs = INT64_MAX / 1000;
+    if (dsd->mStartPositionMs > DataSourceDesc::kMaxTimeMs) {
+        dsd->mStartPositionMs = DataSourceDesc::kMaxTimeMs;
         ALOGW("setDataSource, start poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
     }
-    if (dsd->mEndPositionMs > INT64_MAX / 1000) {
-        dsd->mEndPositionMs = INT64_MAX / 1000;
+    if (dsd->mEndPositionMs > DataSourceDesc::kMaxTimeMs) {
+        dsd->mEndPositionMs = DataSourceDesc::kMaxTimeMs;
         ALOGW("setDataSource, end poistion clamped to %lld ms", (long long)dsd->mStartPositionMs);
     }
     ALOGV("setDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
index 6056ad9..f795478 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
@@ -79,6 +79,7 @@
 void NuPlayer2::GenericSource2::resetDataSource() {
     ALOGV("resetDataSource");
 
+    mDisconnected = false;
     mUri.clear();
     mUriHeaders.clear();
     if (mFd >= 0) {
@@ -196,7 +197,11 @@
         }
 
         sp<AMediaExtractorWrapper> trackExtractor = new AMediaExtractorWrapper(AMediaExtractor_new());
-        trackExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource());
+        if (aSourceWrapper != NULL) {
+            trackExtractor->setDataSource(aSourceWrapper->getAMediaDataSource());
+        } else {
+            trackExtractor->setDataSource(fd, mOffset, mLength);
+        }
 
         const char *mime;
         sp<MetaData> meta = convertMediaFormatWrapperToMetaData(trackFormat);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 7b9ff30..bc17d13 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -1753,8 +1753,13 @@
 }
 
 void NuPlayer2::addEndTimeMonitor() {
-    sp<AMessage> msg = new AMessage(kWhatEOSMonitor, this);
     ++mEOSMonitorGeneration;
+
+    if (mCurrentSourceInfo.mEndTimeUs == DataSourceDesc::kMaxTimeUs) {
+        return;
+    }
+
+    sp<AMessage> msg = new AMessage(kWhatEOSMonitor, this);
     msg->setInt32("generation", mEOSMonitorGeneration);
     mMediaClock->addTimer(msg, mCurrentSourceInfo.mEndTimeUs);
 }
@@ -3216,7 +3221,7 @@
       mSrcId(0),
       mSourceFlags(0),
       mStartTimeUs(0),
-      mEndTimeUs(INT64_MAX) {
+      mEndTimeUs(DataSourceDesc::kMaxTimeUs) {
 }
 
 NuPlayer2::SourceInfo & NuPlayer2::SourceInfo::operator=(const NuPlayer2::SourceInfo &other) {
diff --git a/media/libstagefright/MediaTrack.cpp b/media/libstagefright/MediaTrack.cpp
index 5ad5295..9fbb20e 100644
--- a/media/libstagefright/MediaTrack.cpp
+++ b/media/libstagefright/MediaTrack.cpp
@@ -135,13 +135,13 @@
 
     uint32_t opts = 0;
 
-    if (options->getNonBlocking()) {
+    if (options && options->getNonBlocking()) {
         opts |= CMediaTrackReadOptions::NONBLOCKING;
     }
 
     int64_t seekPosition = 0;
     MediaTrack::ReadOptions::SeekMode seekMode;
-    if (options->getSeekTo(&seekPosition, &seekMode)) {
+    if (options && options->getSeekTo(&seekPosition, &seekMode)) {
         opts |= SEEK;
         opts |= (uint32_t) seekMode;
     }
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index e010b3e..610b961 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -132,6 +132,9 @@
         { "date", METADATA_KEY_DATE },
         { "width", METADATA_KEY_VIDEO_WIDTH },
         { "height", METADATA_KEY_VIDEO_HEIGHT },
+        { "colorstandard", METADATA_KEY_COLOR_STANDARD },
+        { "colortransfer", METADATA_KEY_COLOR_TRANSFER },
+        { "colorrange", METADATA_KEY_COLOR_RANGE },
     };
     static const size_t kNumEntries = sizeof(kKeyMap) / sizeof(kKeyMap[0]);
 
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 231d540..1a01350 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -36,6 +36,7 @@
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaExtractorFactory.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
 #include <media/CharacterEncodingDetector.h>
 
 namespace android {
@@ -403,6 +404,25 @@
     return mMetaData.valueAt(index).string();
 }
 
+void StagefrightMetadataRetriever::parseColorAspects(const sp<MetaData>& meta) {
+    sp<AMessage> format = new AMessage();
+    if (convertMetaDataToMessage(meta, &format) != OK) {
+        return;
+    }
+
+    int32_t standard, transfer, range;
+    if (format->findInt32("color-standard", &standard)
+            && format->findInt32("color-transfer", &transfer)
+            && format->findInt32("color-range", &range)) {
+        ALOGV("found color aspects : standard=%d, transfer=%d, range=%d",
+                standard, transfer, range);
+
+        mMetaData.add(METADATA_KEY_COLOR_STANDARD, String8::format("%d", standard));
+        mMetaData.add(METADATA_KEY_COLOR_TRANSFER, String8::format("%d", transfer));
+        mMetaData.add(METADATA_KEY_COLOR_RANGE, String8::format("%d", range));
+    }
+}
+
 void StagefrightMetadataRetriever::parseMetaData() {
     sp<MetaData> meta = mExtractor->getMetaData();
 
@@ -542,6 +562,8 @@
                 if (!trackMeta->findInt32(kKeyFrameCount, &videoFrameCount)) {
                     videoFrameCount = 0;
                 }
+
+                parseColorAspects(trackMeta);
             } else if (!strncasecmp("image/", mime, 6)) {
                 int32_t isPrimary;
                 if (trackMeta->findInt32(
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 456e2e3..0c6c45b 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1014,6 +1014,56 @@
             msg->setInt32("android._is-hdr", (info & hvcc.kInfoIsHdr) != 0);
         }
 
+        uint32_t isoPrimaries, isoTransfer, isoMatrix, isoRange;
+        if (hvcc.findParam32(kColourPrimaries, &isoPrimaries)
+                && hvcc.findParam32(kTransferCharacteristics, &isoTransfer)
+                && hvcc.findParam32(kMatrixCoeffs, &isoMatrix)
+                && hvcc.findParam32(kVideoFullRangeFlag, &isoRange)) {
+            ALOGV("found iso color aspects : primaris=%d, transfer=%d, matrix=%d, range=%d",
+                    isoPrimaries, isoTransfer, isoMatrix, isoRange);
+
+            ColorAspects aspects;
+            ColorUtils::convertIsoColorAspectsToCodecAspects(
+                    isoPrimaries, isoTransfer, isoMatrix, isoRange, aspects);
+
+            if (aspects.mPrimaries == ColorAspects::PrimariesUnspecified) {
+                int32_t primaries;
+                if (meta->findInt32(kKeyColorPrimaries, &primaries)) {
+                    ALOGV("unspecified primaries found, replaced to %d", primaries);
+                    aspects.mPrimaries = static_cast<ColorAspects::Primaries>(primaries);
+                }
+            }
+            if (aspects.mTransfer == ColorAspects::TransferUnspecified) {
+                int32_t transferFunction;
+                if (meta->findInt32(kKeyTransferFunction, &transferFunction)) {
+                    ALOGV("unspecified transfer found, replaced to %d", transferFunction);
+                    aspects.mTransfer = static_cast<ColorAspects::Transfer>(transferFunction);
+                }
+            }
+            if (aspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified) {
+                int32_t colorMatrix;
+                if (meta->findInt32(kKeyColorMatrix, &colorMatrix)) {
+                    ALOGV("unspecified matrix found, replaced to %d", colorMatrix);
+                    aspects.mMatrixCoeffs = static_cast<ColorAspects::MatrixCoeffs>(colorMatrix);
+                }
+            }
+            if (aspects.mRange == ColorAspects::RangeUnspecified) {
+                int32_t range;
+                if (meta->findInt32(kKeyColorRange, &range)) {
+                    ALOGV("unspecified range found, replaced to %d", range);
+                    aspects.mRange = static_cast<ColorAspects::Range>(range);
+                }
+            }
+
+            int32_t standard, transfer, range;
+            if (ColorUtils::convertCodecColorAspectsToPlatformAspects(
+                    aspects, &range, &standard, &transfer) == OK) {
+                msg->setInt32("color-standard", standard);
+                msg->setInt32("color-transfer", transfer);
+                msg->setInt32("color-range", range);
+            }
+        }
+
         parseHevcProfileLevelFromHvcc((const uint8_t *)data, dataSize, msg);
     } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
         ESDS esds((const char *)data, size);
diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp
index 9921636..768cbd6 100644
--- a/media/libstagefright/foundation/ALooper.cpp
+++ b/media/libstagefright/foundation/ALooper.cpp
@@ -170,7 +170,9 @@
 
     int64_t whenUs;
     if (delayUs > 0) {
-        whenUs = GetNowUs() + delayUs;
+        int64_t nowUs = GetNowUs();
+        whenUs = (delayUs > INT64_MAX - nowUs ? INT64_MAX : nowUs + delayUs);
+
     } else {
         whenUs = GetNowUs();
     }
@@ -208,6 +210,9 @@
 
         if (whenUs > nowUs) {
             int64_t delayUs = whenUs - nowUs;
+            if (delayUs > INT64_MAX / 1000) {
+                delayUs = INT64_MAX / 1000;
+            }
             mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);
 
             return true;
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index a7090ad..c50677a 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -65,6 +65,7 @@
     sp<ImageDecoder> mImageDecoder;
     int mLastImageIndex;
     void parseMetaData();
+    void parseColorAspects(const sp<MetaData>& meta);
     // Delete album art and clear metadata.
     void clearMetadata();
 
diff --git a/media/mtp/MtpPacket.cpp b/media/mtp/MtpPacket.cpp
index 3dd4248..3b298a9 100644
--- a/media/mtp/MtpPacket.cpp
+++ b/media/mtp/MtpPacket.cpp
@@ -157,7 +157,7 @@
                             request->endpoint,
                             request->buffer,
                             request->buffer_length,
-                            0);
+                            1000);
     request->actual_length = result;
     return result;
 }
diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk
index 3c7d29d..65f1a44 100644
--- a/services/soundtrigger/Android.mk
+++ b/services/soundtrigger/Android.mk
@@ -55,6 +55,7 @@
     libaudiohal_deathhandler \
     android.hardware.soundtrigger@2.0 \
     android.hardware.soundtrigger@2.1 \
+    android.hardware.soundtrigger@2.2 \
     android.hardware.audio.common@2.0 \
     android.hidl.allocator@1.0 \
     android.hidl.memory@1.0
diff --git a/services/soundtrigger/SoundTriggerHalHidl.cpp b/services/soundtrigger/SoundTriggerHalHidl.cpp
index adf252e..0f9aa15 100644
--- a/services/soundtrigger/SoundTriggerHalHidl.cpp
+++ b/services/soundtrigger/SoundTriggerHalHidl.cpp
@@ -356,6 +356,50 @@
     return hidlReturn;
 }
 
+int SoundTriggerHalHidl::getModelState(sound_model_handle_t handle,
+                                       struct sound_trigger_recognition_event** event)
+{
+    sp<ISoundTriggerHw> soundtrigger = getService();
+    if (soundtrigger == 0) {
+        return -ENODEV;
+    }
+
+    sp<V2_2_ISoundTriggerHw> soundtrigger_2_2 = toService2_2(soundtrigger);
+    if (soundtrigger_2_2 == 0) {
+        ALOGE("getModelState not supported");
+        return -ENODEV;
+    }
+
+    sp<SoundModel> model = getModel(handle);
+    if (model == 0) {
+        ALOGE("getModelState model not found for handle %u", handle);
+        return -EINVAL;
+    }
+
+    int ret = NO_ERROR;
+    Return<void> hidlReturn;
+    {
+        AutoMutex lock(mHalLock);
+        hidlReturn = soundtrigger_2_2->getModelState(
+            model->mHalHandle,
+            [&](int r, const V2_0_ISoundTriggerHwCallback::RecognitionEvent& halEvent) {
+              ret = r;
+              if (ret != 0) {
+                  ALOGE("getModelState returned error code %d", ret);
+              } else {
+                  *event = convertRecognitionEventFromHal(&halEvent);
+              }
+            });
+    }
+    if (!hidlReturn.isOk()) {
+        ALOGE("getModelState error %s", hidlReturn.description().c_str());
+        free(*event);
+        *event = nullptr;
+        ret = FAILED_TRANSACTION;
+    }
+    return ret;
+}
+
 SoundTriggerHalHidl::SoundTriggerHalHidl(const char *moduleName)
     : mModuleName(moduleName), mNextUniqueId(1)
 {
@@ -388,6 +432,12 @@
     return castResult_2_1.isOk() ? static_cast<sp<V2_1_ISoundTriggerHw>>(castResult_2_1) : nullptr;
 }
 
+sp<V2_2_ISoundTriggerHw> SoundTriggerHalHidl::toService2_2(const sp<ISoundTriggerHw>& s)
+{
+    auto castResult_2_2 = V2_2_ISoundTriggerHw::castFrom(s);
+    return castResult_2_2.isOk() ? static_cast<sp<V2_2_ISoundTriggerHw>>(castResult_2_2) : nullptr;
+}
+
 sp<SoundTriggerHalHidl::SoundModel> SoundTriggerHalHidl::getModel(sound_model_handle_t handle)
 {
     AutoMutex lock(mLock);
diff --git a/services/soundtrigger/SoundTriggerHalHidl.h b/services/soundtrigger/SoundTriggerHalHidl.h
index 0b44ae0..3f4bec3 100644
--- a/services/soundtrigger/SoundTriggerHalHidl.h
+++ b/services/soundtrigger/SoundTriggerHalHidl.h
@@ -27,6 +27,7 @@
 #include "SoundTriggerHalInterface.h"
 #include <android/hardware/soundtrigger/2.0/types.h>
 #include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.2/ISoundTriggerHw.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
 #include <android/hardware/soundtrigger/2.1/ISoundTriggerHwCallback.h>
 
@@ -46,6 +47,8 @@
 using V2_1_ISoundTriggerHwCallback =
         ::android::hardware::soundtrigger::V2_1::ISoundTriggerHwCallback;
 using ::android::hidl::memory::V1_0::IMemory;
+using V2_2_ISoundTriggerHw =
+        ::android::hardware::soundtrigger::V2_2::ISoundTriggerHw;
 
 class SoundTriggerHalHidl : public SoundTriggerHalInterface,
                             public virtual V2_1_ISoundTriggerHwCallback
@@ -92,6 +95,14 @@
          */
         virtual int stopAllRecognitions();
 
+        /* Get the current state of a given model.
+         * Returns 0 or an error code. If successful it also sets indicated the event pointer
+         * and expectes that the caller will free the memory.
+         * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_2 or above.
+         */
+        virtual int getModelState(sound_model_handle_t handle,
+                                  struct sound_trigger_recognition_event** event);
+
         // ISoundTriggerHwCallback
         virtual ::android::hardware::Return<void> recognitionCallback(
                 const V2_0_ISoundTriggerHwCallback::RecognitionEvent& event, CallbackCookie cookie);
@@ -182,6 +193,7 @@
         uint32_t nextUniqueId();
         sp<ISoundTriggerHw> getService();
         sp<V2_1_ISoundTriggerHw> toService2_1(const sp<ISoundTriggerHw>& s);
+        sp<V2_2_ISoundTriggerHw> toService2_2(const sp<ISoundTriggerHw>& s);
         sp<SoundModel> getModel(sound_model_handle_t handle);
         sp<SoundModel> removeModel(sound_model_handle_t handle);
 
diff --git a/services/soundtrigger/SoundTriggerHalInterface.h b/services/soundtrigger/SoundTriggerHalInterface.h
index c083195..076ca23 100644
--- a/services/soundtrigger/SoundTriggerHalInterface.h
+++ b/services/soundtrigger/SoundTriggerHalInterface.h
@@ -71,6 +71,14 @@
          */
         virtual int stopAllRecognitions() = 0;
 
+        /* Get the current state of a given model.
+         * Returns 0 or an error code. If successful it also sets indicated the event pointer
+         * and expectes that the caller will free the memory.
+         * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_2 or above.
+         */
+        virtual int getModelState(sound_model_handle_t handle,
+                                  struct sound_trigger_recognition_event** event) = 0;
+
 protected:
         SoundTriggerHalInterface() {}
 };
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index eb9cd1d..79e9e88 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -717,6 +717,40 @@
     return NO_ERROR;
 }
 
+status_t SoundTriggerHwService::Module::getModelState(sound_model_handle_t handle,
+                                                      sp<IMemory>& eventMemory)
+{
+    ALOGV("getModelState() model handle %d", handle);
+    if (mHalInterface == 0) {
+        return NO_INIT;
+    }
+    AutoMutex lock(mLock);
+    sp<Model> model = getModel(handle);
+    if (model == 0) {
+        return BAD_VALUE;
+    }
+
+    if (model->mState != Model::STATE_ACTIVE) {
+        return INVALID_OPERATION;
+    }
+
+    if (model->mType != SOUND_MODEL_TYPE_GENERIC) {
+        return BAD_VALUE;
+    }
+
+    struct sound_trigger_recognition_event* event = nullptr;
+    status_t status = mHalInterface->getModelState(handle, &event);
+    if (status == NO_ERROR) {
+        sp<SoundTriggerHwService> service;
+        service = mService.promote();
+        if (service != 0) {
+            eventMemory = service->prepareRecognitionEvent(event);
+        }
+        free(event);
+    }
+    return status;
+}
+
 void SoundTriggerHwService::Module::onCallbackEvent(const sp<CallbackEvent>& event)
 {
     ALOGV("onCallbackEvent type %d", event->mType);
@@ -1018,6 +1052,22 @@
     return module->stopRecognition(handle);
 }
 
+status_t SoundTriggerHwService::ModuleClient::getModelState(sound_model_handle_t handle,
+                                                            sp<IMemory>& eventMemory)
+{
+    ALOGV("getModelState() model handle %d", handle);
+    if (!captureHotwordAllowed(IPCThreadState::self()->getCallingPid(),
+                               IPCThreadState::self()->getCallingUid())) {
+        return PERMISSION_DENIED;
+    }
+
+    sp<Module> module = mModule.promote();
+    if (module == 0) {
+        return NO_INIT;
+    }
+    return module->getModelState(handle, eventMemory);
+}
+
 void SoundTriggerHwService::ModuleClient::setCaptureState_l(bool active)
 {
     ALOGV("ModuleClient::setCaptureState_l %d", active);
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
index 708fc98..c222cd9 100644
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -122,6 +122,8 @@
        virtual status_t startRecognition(sound_model_handle_t handle,
                                          const sp<IMemory>& dataMemory);
        virtual status_t stopRecognition(sound_model_handle_t handle);
+       virtual status_t getModelState(sound_model_handle_t handle,
+                                      sp<IMemory>& eventMemory);
 
        sp<SoundTriggerHalInterface> halInterface() const { return mHalInterface; }
        struct sound_trigger_module_descriptor descriptor() { return mDescriptor; }
@@ -169,6 +171,8 @@
        virtual status_t startRecognition(sound_model_handle_t handle,
                                          const sp<IMemory>& dataMemory);
        virtual status_t stopRecognition(sound_model_handle_t handle);
+       virtual status_t getModelState(sound_model_handle_t handle,
+                                      sp<IMemory>& eventMemory);
 
        virtual status_t dump(int fd, const Vector<String16>& args);
 
diff --git a/soundtrigger/ISoundTrigger.cpp b/soundtrigger/ISoundTrigger.cpp
index 25332a4..32882f1 100644
--- a/soundtrigger/ISoundTrigger.cpp
+++ b/soundtrigger/ISoundTrigger.cpp
@@ -32,6 +32,7 @@
     UNLOAD_SOUND_MODEL,
     START_RECOGNITION,
     STOP_RECOGNITION,
+    GET_MODEL_STATE,
 };
 
 class BpSoundTrigger: public BpInterface<ISoundTrigger>
@@ -113,6 +114,22 @@
         return status;
     }
 
+    virtual status_t getModelState(sound_model_handle_t handle,
+                                   sp<IMemory>& eventMemory)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor());
+        data.write(&handle, sizeof(sound_model_handle_t));
+        status_t status = remote()->transact(GET_MODEL_STATE, data, &reply);
+        if (status == NO_ERROR) {
+            status = (status_t)reply.readInt32();
+            if (status == NO_ERROR) {
+                eventMemory = interface_cast<IMemory>(reply.readStrongBinder());
+            }
+        }
+        return status;
+    }
+
 };
 
 IMPLEMENT_META_INTERFACE(SoundTrigger, "android.hardware.ISoundTrigger");
@@ -169,6 +186,24 @@
             reply->writeInt32(status);
             return NO_ERROR;
         }
+        case GET_MODEL_STATE: {
+            CHECK_INTERFACE(ISoundTrigger, data, reply);
+            sound_model_handle_t handle;
+            status_t status = UNKNOWN_ERROR;
+            status_t ret = data.read(&handle, sizeof(sound_model_handle_t));
+            if (ret == NO_ERROR) {
+                sp<IMemory> eventMemory;
+                status = getModelState(handle, eventMemory);
+                if (eventMemory != NULL) {
+                    ret = reply->writeStrongBinder(
+                        IInterface::asBinder(eventMemory));
+                } else {
+                    ret = NO_MEMORY;
+                }
+            }
+            reply->writeInt32(status);
+            return ret;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp
index 289b7b1..bb0650f 100644
--- a/soundtrigger/SoundTrigger.cpp
+++ b/soundtrigger/SoundTrigger.cpp
@@ -188,6 +188,16 @@
     return mISoundTrigger->stopRecognition(handle);
 }
 
+status_t SoundTrigger::getModelState(sound_model_handle_t handle,
+                                     sp<IMemory>& eventMemory)
+{
+    Mutex::Autolock _l(mLock);
+    if (mISoundTrigger == 0) {
+        return NO_INIT;
+    }
+    return mISoundTrigger->getModelState(handle, eventMemory);
+}
+
 // BpSoundTriggerClient
 void SoundTrigger::onRecognitionEvent(const sp<IMemory>& eventMemory)
 {