Merge "Notify Errors Appropriately from SoftMPEG2" into mnc-dev am: 74a2af11b9 am: 0817640c9f am: 41c60ea30e am: e2424e9895  -s ours am: a51cfb3a00  -s ours am: d77a443db4  -s ours am: 9dd993e516  -s ours am: 3ed228d80c  -s ours am: e003b8931d  -s ours am: 8c8012d126  -s ours
am: 7f145e886d  -s ours

Change-Id: I39070568218d9d5868690b7fb07b4f4c1a745785
diff --git a/camera/Android.bp b/camera/Android.bp
index 7ff3e89..64185e1 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -21,7 +21,6 @@
         export_aidl_headers: true,
         local_include_dirs: ["aidl"],
         include_dirs: [
-            "frameworks/base/core/java",
             "frameworks/native/aidl/gui",
         ],
     },
@@ -61,6 +60,7 @@
         "libbinder",
         "libgui",
         "libcamera_metadata",
+        "libnativewindow",
     ],
 
     include_dirs: [
@@ -75,4 +75,5 @@
         "-Wall",
         "-Wextra",
     ],
+
 }
diff --git a/drm/mediadrm/plugins/clearkey/Android.bp b/drm/mediadrm/plugins/clearkey/Android.bp
index 6af7cd8..f3ce65c 100644
--- a/drm/mediadrm/plugins/clearkey/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/Android.bp
@@ -38,12 +38,17 @@
     shared_libs: [
         "libcrypto",
         "liblog",
-        "libstagefright_foundation",
+        "libstagefright_foundation_vendor",
         "libutils",
     ],
 
     static_libs: ["libjsmn"],
 
+    include_dirs: [
+        "frameworks/native/include",
+        "frameworks/av/include",
+    ],
+
     export_include_dirs: ["."],
     export_static_lib_headers: ["libjsmn"],
 }
diff --git a/drm/mediadrm/plugins/clearkey/tests/Android.bp b/drm/mediadrm/plugins/clearkey/tests/Android.bp
index 1b208ad..976c590 100644
--- a/drm/mediadrm/plugins/clearkey/tests/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/tests/Android.bp
@@ -19,6 +19,7 @@
 
 cc_test {
     name: "ClearKeyDrmUnitTest",
+    vendor: true,
 
     srcs: [
         "AesCtrDecryptorUnittest.cpp",
@@ -30,7 +31,7 @@
         "libcrypto",
         "libdrmclearkeyplugin",
         "liblog",
-        "libstagefright_foundation",
+        "libstagefright_foundation_vendor",
         "libutils",
     ],
 }
diff --git a/include/media/omx/1.0/WGraphicBufferSource.h b/include/media/omx/1.0/WGraphicBufferSource.h
index 397e576..bf3be9a 100644
--- a/include/media/omx/1.0/WGraphicBufferSource.h
+++ b/include/media/omx/1.0/WGraphicBufferSource.h
@@ -74,6 +74,7 @@
     BnStatus setTimeLapseConfig(double fps, double captureFps) override;
     BnStatus setStartTimeUs(int64_t startTimeUs) override;
     BnStatus setStopTimeUs(int64_t stopTimeUs) override;
+    BnStatus getStopTimeOffsetUs(int64_t *stopTimeOffsetUs) override;
     BnStatus setColorAspects(int32_t aspects) override;
     BnStatus setTimeOffsetUs(int64_t timeOffsetsUs) override;
     BnStatus signalEndOfInputStream() override;
diff --git a/include/media/stagefright b/include/media/stagefright
index ae324a8..5393f68 120000
--- a/include/media/stagefright
+++ b/include/media/stagefright
@@ -1 +1 @@
-../../media/libstagefright/include
\ No newline at end of file
+../../media/libstagefright/include/media/stagefright/
\ No newline at end of file
diff --git a/media/libaaudio/examples/input_monitor/static/Android.mk b/media/libaaudio/examples/input_monitor/static/Android.mk
index 61fc3b8..80a3906 100644
--- a/media/libaaudio/examples/input_monitor/static/Android.mk
+++ b/media/libaaudio/examples/input_monitor/static/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := examples
+LOCAL_MODULE_TAGS := samples
 LOCAL_C_INCLUDES := \
     $(call include-path-for, audio-utils) \
     frameworks/av/media/libaaudio/include \
diff --git a/media/libaaudio/examples/write_sine/static/Android.mk b/media/libaaudio/examples/write_sine/static/Android.mk
index 40dca34..1f8dcd9 100644
--- a/media/libaaudio/examples/write_sine/static/Android.mk
+++ b/media/libaaudio/examples/write_sine/static/Android.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := examples
+LOCAL_MODULE_TAGS := samples
 LOCAL_C_INCLUDES := \
     $(call include-path-for, audio-utils) \
     frameworks/av/media/libaaudio/src \
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index e749ac4..d29aa74 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -1272,6 +1272,7 @@
     {
         AutoMutex _l(mMyLock);
         if (mPaused) {
+            // TODO check return value and handle or log
             mMyCond.wait(mMyLock);
             // caller will check for exitPending()
             return true;
@@ -1282,8 +1283,10 @@
         }
         if (mPausedInt) {
             if (mPausedNs > 0) {
+                // TODO check return value and handle or log
                 (void) mMyCond.waitRelative(mMyLock, mPausedNs);
             } else {
+                // TODO check return value and handle or log
                 mMyCond.wait(mMyLock);
             }
             mPausedInt = false;
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index ffb7703..98ec7d7 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -908,13 +908,13 @@
             effectiveRate, effectiveSpeed, effectivePitch);
 
     if (!isAudioPlaybackRateValid(playbackRateTemp)) {
-        ALOGV("setPlaybackRate(%f, %f) failed (effective rate out of bounds)",
+        ALOGW("setPlaybackRate(%f, %f) failed (effective rate out of bounds)",
                 playbackRate.mSpeed, playbackRate.mPitch);
         return BAD_VALUE;
     }
     // Check if the buffer size is compatible.
     if (!isSampleRateSpeedAllowed_l(effectiveRate, effectiveSpeed)) {
-        ALOGV("setPlaybackRate(%f, %f) failed (buffer size)",
+        ALOGW("setPlaybackRate(%f, %f) failed (buffer size)",
                 playbackRate.mSpeed, playbackRate.mPitch);
         return BAD_VALUE;
     }
@@ -922,13 +922,13 @@
     // Check resampler ratios are within bounds
     if ((uint64_t)effectiveRate > (uint64_t)mSampleRate *
             (uint64_t)AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
-        ALOGV("setPlaybackRate(%f, %f) failed. Resample rate exceeds max accepted value",
+        ALOGW("setPlaybackRate(%f, %f) failed. Resample rate exceeds max accepted value",
                 playbackRate.mSpeed, playbackRate.mPitch);
         return BAD_VALUE;
     }
 
     if ((uint64_t)effectiveRate * (uint64_t)AUDIO_RESAMPLER_UP_RATIO_MAX < (uint64_t)mSampleRate) {
-        ALOGV("setPlaybackRate(%f, %f) failed. Resample rate below min accepted value",
+        ALOGW("setPlaybackRate(%f, %f) failed. Resample rate below min accepted value",
                         playbackRate.mSpeed, playbackRate.mPitch);
         return BAD_VALUE;
     }
@@ -1247,9 +1247,27 @@
     return mStreamType;
 }
 
+uint32_t AudioTrack::latency()
+{
+    AutoMutex lock(mLock);
+    updateLatency_l();
+    return mLatency;
+}
+
 // -------------------------------------------------------------------------
 
 // must be called with mLock held
+void AudioTrack::updateLatency_l()
+{
+    status_t status = AudioSystem::getLatency(mOutput, &mAfLatency);
+    if (status != NO_ERROR) {
+        ALOGW("getLatency(%d) failed status %d", mOutput, status);
+    } else {
+        // FIXME don't believe this lie
+        mLatency = mAfLatency + (1000 * mFrameCount) / mSampleRate;
+    }
+}
+
 status_t AudioTrack::createTrack_l()
 {
     const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
@@ -1416,6 +1434,9 @@
 
     pid_t tid = -1;
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
+        // It is currently meaningless to request SCHED_FIFO for a Java thread.  Even if the
+        // application-level code follows all non-blocking design rules, the language runtime
+        // doesn't also follow those rules, so the thread will not benefit overall.
         if (mAudioTrackThread != 0 && !mThreadCanCallJava) {
             tid = mAudioTrackThread->getTid();
         }
@@ -1541,11 +1562,9 @@
     }
 
     mAudioTrack->attachAuxEffect(mAuxEffectId);
-    // FIXME doesn't take into account speed or future sample rate changes (until restoreTrack)
-    // FIXME don't believe this lie
-    mLatency = mAfLatency + (1000*frameCount) / mSampleRate;
-
     mFrameCount = frameCount;
+    updateLatency_l();  // this refetches mAfLatency and sets mLatency
+
     // If IAudioTrack is re-created, don't let the requested frameCount
     // decrease.  This can confuse clients that cache frameCount().
     if (frameCount > mReqFrameCount) {
@@ -2315,8 +2334,9 @@
     return mPosition;
 }
 
-bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const
+bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed)
 {
+    updateLatency_l();
     // applicable for mixing tracks only (not offloaded or direct)
     if (mStaticProxy != 0) {
         return true; // static tracks do not have issues with buffer sizing.
@@ -2324,9 +2344,14 @@
     const size_t minFrameCount =
             calculateMinFrameCount(mAfLatency, mAfFrameCount, mAfSampleRate, sampleRate, speed
                 /*, 0 mNotificationsPerBufferReq*/);
-    ALOGV("isSampleRateSpeedAllowed_l mFrameCount %zu  minFrameCount %zu",
+    const bool allowed = mFrameCount >= minFrameCount;
+    ALOGD_IF(!allowed,
+            "isSampleRateSpeedAllowed_l denied "
+            "mAfLatency:%u  mAfFrameCount:%zu  mAfSampleRate:%u  sampleRate:%u  speed:%f "
+            "mFrameCount:%zu < minFrameCount:%zu",
+            mAfLatency, mAfFrameCount, mAfSampleRate, sampleRate, speed,
             mFrameCount, minFrameCount);
-    return mFrameCount >= minFrameCount;
+    return allowed;
 }
 
 status_t AudioTrack::setParameters(const String8& keyValuePairs)
@@ -2470,6 +2495,7 @@
             status = ets.getBestTimestamp(&timestamp, &location);
 
             if (status == OK) {
+                updateLatency_l();
                 // It is possible that the best location has moved from the kernel to the server.
                 // In this case we adjust the position from the previous computed latency.
                 if (location == ExtendedTimestamp::LOCATION_SERVER) {
@@ -2941,6 +2967,7 @@
     {
         AutoMutex _l(mMyLock);
         if (mPaused) {
+            // TODO check return value and handle or log
             mMyCond.wait(mMyLock);
             // caller will check for exitPending()
             return true;
@@ -2950,9 +2977,12 @@
             mPausedInt = false;
         }
         if (mPausedInt) {
+            // TODO use futex instead of condition, for event flag "or"
             if (mPausedNs > 0) {
+                // TODO check return value and handle or log
                 (void) mMyCond.waitRelative(mMyLock, mPausedNs);
             } else {
+                // TODO check return value and handle or log
                 mMyCond.wait(mMyLock);
             }
             mPausedInt = false;
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 858b5cc..14feada 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -62,7 +62,7 @@
     SET_VOICE_VOLUME,
     GET_RENDER_POSITION,
     GET_INPUT_FRAMES_LOST,
-    NEW_AUDIO_SESSION_ID,
+    NEW_AUDIO_UNIQUE_ID,
     ACQUIRE_AUDIO_SESSION_ID,
     RELEASE_AUDIO_SESSION_ID,
     QUERY_NUM_EFFECTS,
@@ -80,7 +80,7 @@
     RELEASE_AUDIO_PATCH,
     LIST_AUDIO_PATCHES,
     SET_AUDIO_PORT_CONFIG,
-    GET_AUDIO_HW_SYNC,
+    GET_AUDIO_HW_SYNC_FOR_SESSION,
     SYSTEM_READY,
     FRAME_COUNT_HAL,
 };
@@ -628,8 +628,8 @@
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32((int32_t) use);
-        status_t status = remote()->transact(NEW_AUDIO_SESSION_ID, data, &reply);
-        audio_unique_id_t id = AUDIO_SESSION_ALLOCATE;
+        status_t status = remote()->transact(NEW_AUDIO_UNIQUE_ID, data, &reply);
+        audio_unique_id_t id = AUDIO_UNIQUE_ID_ALLOCATE;
         if (status == NO_ERROR) {
             id = reply.readInt32();
         }
@@ -912,7 +912,7 @@
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(sessionId);
-        status_t status = remote()->transact(GET_AUDIO_HW_SYNC, data, &reply);
+        status_t status = remote()->transact(GET_AUDIO_HW_SYNC_FOR_SESSION, data, &reply);
         if (status != NO_ERROR) {
             return AUDIO_HW_SYNC_INVALID;
         }
@@ -1262,7 +1262,7 @@
             reply->writeInt32((int32_t) getInputFramesLost(ioHandle));
             return NO_ERROR;
         } break;
-        case NEW_AUDIO_SESSION_ID: {
+        case NEW_AUDIO_UNIQUE_ID: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             reply->writeInt32(newAudioUniqueId((audio_unique_id_use_t) data.readInt32()));
             return NO_ERROR;
@@ -1466,7 +1466,7 @@
             reply->writeInt32(status);
             return NO_ERROR;
         } break;
-        case GET_AUDIO_HW_SYNC: {
+        case GET_AUDIO_HW_SYNC_FOR_SESSION: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             reply->writeInt32(getAudioHwSyncForSession((audio_session_t) data.readInt32()));
             return NO_ERROR;
diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h
index 87ada76..2bd2d01 100644
--- a/media/libaudioclient/include/media/AudioMixer.h
+++ b/media/libaudioclient/include/media/AudioMixer.h
@@ -286,7 +286,7 @@
         process_hook_t  hook;   // one of process__*, never NULL
         int32_t         *outputTemp;
         int32_t         *resampleTemp;
-        NBLog::Writer*  mLog;
+        NBLog::Writer*  mNBLogWriter;   // associated NBLog::Writer or &mDummyLog
         int32_t         reserved[1];
         // FIXME allocate dynamically to save some memory when maxNumTracks < MAX_NUM_TRACKS
         track_t         tracks[MAX_NUM_TRACKS] __attribute__((aligned(32)));
@@ -301,9 +301,11 @@
 
     const uint32_t  mSampleRate;
 
-    NBLog::Writer   mDummyLog;
+    NBLog::Writer   mDummyLogWriter;
 public:
-    void            setLog(NBLog::Writer* log);
+    // Called by FastMixer to inform AudioMixer of it's associated NBLog::Writer.
+    // FIXME It would be safer to use TLS for this, so we don't accidentally use wrong one.
+    void            setNBLogWriter(NBLog::Writer* log);
 private:
     state_t         mState __attribute__((aligned(32)));
 
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index a4c8d53..5d73df3 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -326,7 +326,7 @@
      * This includes the latency due to AudioTrack buffer size, AudioMixer (if any)
      * and audio hardware driver.
      */
-            uint32_t    latency() const     { return mLatency; }
+            uint32_t    latency();
 
     /* Returns the number of application-level buffer underruns
      * since the AudioTrack was created.
@@ -927,6 +927,8 @@
 
             // caller must hold lock on mLock for all _l methods
 
+            void updateLatency_l(); // updates mAfLatency and mLatency from AudioSystem cache
+
             status_t createTrack_l();
 
             // can only be called when mState != STATE_ACTIVE
@@ -962,7 +964,7 @@
             Modulo<uint32_t> updateAndGetPosition_l();
 
             // check sample rate and speed is compatible with AudioTrack
-            bool     isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const;
+            bool     isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed);
 
             void     restartIfDisabled();
 
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index ae1be09..238925d 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -114,7 +114,7 @@
     mState.hook         = process__nop;
     mState.outputTemp   = NULL;
     mState.resampleTemp = NULL;
-    mState.mLog         = &mDummyLog;
+    mState.mNBLogWriter = &mDummyLogWriter;
     // mState.reserved
 
     // FIXME Most of the following initialization is probably redundant since
@@ -145,9 +145,9 @@
     delete [] mState.resampleTemp;
 }
 
-void AudioMixer::setLog(NBLog::Writer *log)
+void AudioMixer::setNBLogWriter(NBLog::Writer *logWriter)
 {
-    mState.mLog = log;
+    mState.mNBLogWriter = logWriter;
 }
 
 static inline audio_format_t selectMixerInFormat(audio_format_t inputFormat __unused) {
diff --git a/media/libcpustats/Android.bp b/media/libcpustats/Android.bp
index 3ea96c9..8fcd8a4 100644
--- a/media/libcpustats/Android.bp
+++ b/media/libcpustats/Android.bp
@@ -10,4 +10,13 @@
         "-Werror",
         "-Wall",
     ],
+
+    host_supported: true,
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+
 }
diff --git a/media/libcpustats/ThreadCpuUsage.cpp b/media/libcpustats/ThreadCpuUsage.cpp
index b43b36c..4b7549f 100644
--- a/media/libcpustats/ThreadCpuUsage.cpp
+++ b/media/libcpustats/ThreadCpuUsage.cpp
@@ -26,6 +26,11 @@
 
 #include <cpustats/ThreadCpuUsage.h>
 
+// implemented by host, but not declared in <string.h> as FreeBSD does
+extern "C" {
+    extern size_t strlcpy(char *dst, const char *src, size_t dstsize);
+}
+
 namespace android {
 
 bool ThreadCpuUsage::setEnabled(bool isEnabled)
diff --git a/media/libeffects/downmix/Android.mk b/media/libeffects/downmix/Android.mk
index 09793d1..73f6ef5 100644
--- a/media/libeffects/downmix/Android.mk
+++ b/media/libeffects/downmix/Android.mk
@@ -23,4 +23,5 @@
 LOCAL_CFLAGS += -fvisibility=hidden
 LOCAL_CFLAGS += -Wall -Werror
 
+LOCAL_HEADER_LIBRARIES += libhardware_headers
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/lvm/wrapper/Android.mk b/media/libeffects/lvm/wrapper/Android.mk
index f92fb95..efd30fb 100644
--- a/media/libeffects/lvm/wrapper/Android.mk
+++ b/media/libeffects/lvm/wrapper/Android.mk
@@ -30,6 +30,7 @@
 	$(LOCAL_PATH)/../lib/Bundle/lib/ \
 	$(call include-path-for, audio-effects)
 
+LOCAL_HEADER_LIBRARIES += libhardware_headers
 include $(BUILD_SHARED_LIBRARY)
 
 
@@ -62,4 +63,5 @@
     $(LOCAL_PATH)/../lib/Reverb/lib/ \
     $(call include-path-for, audio-effects)
 
+LOCAL_HEADER_LIBRARIES += libhardware_headers
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
index 06d8237..358da8b 100644
--- a/media/libeffects/preprocessing/Android.mk
+++ b/media/libeffects/preprocessing/Android.mk
@@ -3,6 +3,7 @@
 # audio preprocessing wrapper
 include $(CLEAR_VARS)
 
+LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE:= libaudiopreprocessing
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_RELATIVE_PATH := soundfx
@@ -31,4 +32,5 @@
 LOCAL_CFLAGS += -fvisibility=hidden
 LOCAL_CFLAGS += -Wall -Werror
 
+LOCAL_HEADER_LIBRARIES += libhardware_headers
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk
index 8687e1b..70409de 100644
--- a/media/libeffects/visualizer/Android.mk
+++ b/media/libeffects/visualizer/Android.mk
@@ -22,4 +22,5 @@
 	$(call include-path-for, audio-effects)
 
 
+LOCAL_HEADER_LIBRARIES += libhardware_headers
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index e9b99b4..8cf8005 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -13,9 +13,12 @@
         "-Wno-error=deprecated-declarations",
         "-Wall",
     ],
-    shared: {
-      shared_libs: ["libutils", "liblog"],
-    },
+    shared_libs: ["libutils", "liblog", "libgui"],
+    header_libs: [
+        "libmedia_headers",
+        "libaudioclient_headers",
+        "libaudio_system_headers",
+    ],
     clang: true,
 }
 
diff --git a/media/libmedia/aidl/android/IGraphicBufferSource.aidl b/media/libmedia/aidl/android/IGraphicBufferSource.aidl
index f3c7abc..12c2767 100644
--- a/media/libmedia/aidl/android/IGraphicBufferSource.aidl
+++ b/media/libmedia/aidl/android/IGraphicBufferSource.aidl
@@ -31,6 +31,7 @@
     void setTimeLapseConfig(double fps, double captureFps);
     void setStartTimeUs(long startTimeUs);
     void setStopTimeUs(long stopTimeUs);
+    long getStopTimeOffsetUs();
     void setColorAspects(int aspects);
     void setTimeOffsetUs(long timeOffsetsUs);
     void signalEndOfInputStream();
diff --git a/media/libmedia/include/media/OMXBuffer.h b/media/libmedia/include/media/OMXBuffer.h
index 6f79182..3e84858 100644
--- a/media/libmedia/include/media/OMXBuffer.h
+++ b/media/libmedia/include/media/OMXBuffer.h
@@ -19,7 +19,6 @@
 
 #include <cutils/native_handle.h>
 #include <media/IOMX.h>
-#include <system/window.h>
 #include <utils/StrongPointer.h>
 #include <hidl/HidlSupport.h>
 
diff --git a/media/libmedia/include/media/convert.h b/media/libmedia/include/media/convert.h
index 980b5d5..036c611 100644
--- a/media/libmedia/include/media/convert.h
+++ b/media/libmedia/include/media/convert.h
@@ -119,7 +119,7 @@
     /* Check for a '-' in string. If type is unsigned and a - is found, the
      * parsing fails. This is made necessary because "-1" is read as 65535 for
      * uint16_t, for example */
-    if (str.find("-") != std::string::npos
+    if (str.find('-') != std::string::npos
         && !std::numeric_limits<T>::is_signed) {
         return false;
     }
diff --git a/media/libmedia/omx/1.0/WGraphicBufferSource.cpp b/media/libmedia/omx/1.0/WGraphicBufferSource.cpp
index 4c543fa..31d1df9 100644
--- a/media/libmedia/omx/1.0/WGraphicBufferSource.cpp
+++ b/media/libmedia/omx/1.0/WGraphicBufferSource.cpp
@@ -67,6 +67,14 @@
     return toBinderStatus(mBase->setStopTimeUs(stopTimeUs));
 }
 
+BnStatus LWGraphicBufferSource::getStopTimeOffsetUs(
+        int64_t *stopTimeOffsetUs) {
+    return toBinderStatus(mBase->getStopTimeOffsetUs(
+            [stopTimeOffsetUs](auto, auto offsetUs) {
+                *stopTimeOffsetUs = offsetUs;
+            }));
+}
+
 BnStatus LWGraphicBufferSource::setColorAspects(
         int32_t aspects) {
     return toBinderStatus(mBase->setColorAspects(
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index e1d762f..89354d6 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1864,7 +1864,7 @@
         mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId);
     } else if (mVideoSource == VIDEO_SOURCE_SURFACE) {
         // surface source doesn't need large initial delay
-        mStartTimeOffsetMs = 200;
+        mStartTimeOffsetMs = 100;
     }
     if (mStartTimeOffsetMs > 0) {
         writer->setStartTimeOffsetMs(mStartTimeOffsetMs);
@@ -1982,10 +1982,12 @@
         mCameraSourceTimeLapse = NULL;
     }
 
-    if (mVideoEncoderSource != NULL) {
-        int64_t stopTimeUs = systemTime() / 1000;
-        sp<MetaData> meta = new MetaData;
-        err = mVideoEncoderSource->setStopStimeUs(stopTimeUs);
+    int64_t stopTimeUs = systemTime() / 1000;
+    for (const auto &source : { mAudioEncoderSource, mVideoEncoderSource }) {
+        if (source != nullptr && OK != source->setStopTimeUs(stopTimeUs)) {
+            ALOGW("Failed to set stopTime %lld us for %s",
+                    (long long)stopTimeUs, source->isVideo() ? "Video" : "Audio");
+        }
     }
 
     if (mWriter != NULL) {
diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index 9cccfc4..48ffb01 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -14,10 +14,85 @@
  * limitations under the License.
  */
 
+/*
+* Documentation: Workflow summary for histogram data processing:
+* For more details on FIFO, please see system/media/audio_utils; doxygen
+* TODO: add this documentation to doxygen once it is further developed
+* 1) writing the data to a buffer
+* onWork
+*     Called every period length (e.g., 4ms)
+*     Calls LOG_HIST_TS
+* LOG_HIST_TS
+*     Hashes file name and line number
+*     calls NBLOG::Writer::logHistTS once
+* NBLOG::Writer::logHistTS
+*     calls NBLOG::Writer::log on hash and current timestamp
+*     time is in CLOCK_MONOTONIC converted to ns
+* NBLOG::Writer::log(Event, const void*, size_t)
+*     Initializes Entry, a struct containing one log entry
+*     Entry contains the event type (mEvent), data length (mLength),
+*     and data pointer (mData)
+*     TODO: why mLength (max length of buffer data)  must be <= kMaxLength = 255?
+*     calls NBLOG::Writer::log(Entry *, bool)
+* NBLog::Writer::log(Entry *, bool)
+*     Calls copyEntryDataAt to format data as follows in temp array:
+*     [type][length][data ... ][length]
+*     calls audio_utils_fifo_writer.write on temp
+* audio_utils_fifo_writer.write
+*     calls obtain(), memcpy (reference in doxygen)
+*     returns number of frames written
+* ssize_t audio_utils_fifo_reader::obtain
+*     Determines readable buffer section via pointer arithmetic on reader
+*     and writer pointers
+*
+* 2) reading the data from shared memory
+* Thread::threadloop()
+*     TODO: add description?
+* NBLog::MergeThread::threadLoop()
+*     calls NBLog::Merger::merge
+* NBLog::Merger::merge
+*     for each reader in vector of class NamedReader,
+*     callsNamedReader::reader()->getSnapshot
+*     TODO: check whether the rest of this function is relevant
+* NBLog::Reader::getSnapshot
+*     copies snapshot of reader's fifo buffer into its own buffer
+*     calls mFifoReader->obtain to find readable data
+*     sets snapshot.begin() and .end() iterators to boundaries of valid entries
+*     moves the fifo reader index to after the last entry read
+*     in this case, the buffer is in shared memory. in (3), the buffer is private
+*
+* 3) reading the data from private buffer
+* MediaLogService::dump
+*     calls NBLog::Reader::dump(int) on instance of subclass mergeReader
+* NBLog::Reader::dump(int)
+*     calls getSnapshot on the current reader
+*     calls dump(int, size_t, Snapshot)
+* NBLog::Reader::dump(int, size, snapshot)
+*     iterates through snapshot's events and switches based on their type
+*     (string, timestamp, etc...)
+*     In the case of EVENT_HISTOGRAM_ENTRY_TS, adds a list of timestamp sequences
+*     (histogram entry) to NBLog::mHists
+*     In the case of EVENT_HISTOGRAM_FLUSH, calls drawHistogram on each element in
+*     the list and erases it
+*     TODO: when do these events occur?
+* NBLog::drawHistogram
+*     input: timestamp array
+*     buckets this to a histogram and prints
+*
+*/
+
 #define LOG_TAG "NBLog"
 //#define LOG_NDEBUG 0
 
+#include <algorithm>
 #include <climits>
+#include <deque>
+#include <fstream>
+// #include <inttypes.h>
+#include <iostream>
+#include <math.h>
+#include <numeric>
+#include <vector>
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -27,16 +102,18 @@
 #include <new>
 #include <audio_utils/roundup.h>
 #include <media/nbaio/NBLog.h>
+// #include <utils/CallStack.h> // used to print callstack
 #include <utils/Log.h>
 #include <utils/String8.h>
 
 #include <queue>
+#include <utility>
 
 namespace android {
 
-int NBLog::Entry::readAt(size_t offset) const
+int NBLog::Entry::copyEntryDataAt(size_t offset) const
 {
-    // FIXME This is too slow, despite the name it is used during writing
+    // FIXME This is too slow
     if (offset == 0)
         return mEvent;
     else if (offset == 1)
@@ -51,12 +128,29 @@
 
 // ---------------------------------------------------------------------------
 
-NBLog::FormatEntry::FormatEntry(const uint8_t *entry) : mEntry(entry) {
-    ALOGW_IF(entry[offsetof(struct entry, type)] != EVENT_START_FMT,
-        "Created format entry with invalid event type %d", entry[offsetof(struct entry, type)]);
+/*static*/
+std::unique_ptr<NBLog::AbstractEntry> NBLog::AbstractEntry::buildEntry(const uint8_t *ptr) {
+    const uint8_t type = EntryIterator(ptr)->type;
+    switch (type) {
+    case EVENT_START_FMT:
+        return std::make_unique<FormatEntry>(FormatEntry(ptr));
+    case EVENT_HISTOGRAM_FLUSH:
+    case EVENT_HISTOGRAM_ENTRY_TS:
+        return std::make_unique<HistogramEntry>(HistogramEntry(ptr));
+    default:
+        ALOGW("Tried to create AbstractEntry of type %d", type);
+        return nullptr;
+    }
 }
 
-NBLog::FormatEntry::FormatEntry(const NBLog::FormatEntry::iterator &it) : FormatEntry(it.ptr) {}
+NBLog::AbstractEntry::AbstractEntry(const uint8_t *entry) : mEntry(entry) {
+}
+
+// ---------------------------------------------------------------------------
+
+NBLog::EntryIterator NBLog::FormatEntry::begin() const {
+    return EntryIterator(mEntry);
+}
 
 const char *NBLog::FormatEntry::formatString() const {
     return (const char*) mEntry + offsetof(entry, data);
@@ -66,12 +160,14 @@
     return mEntry[offsetof(entry, length)];
 }
 
-NBLog::FormatEntry::iterator NBLog::FormatEntry::args() const {
+NBLog::EntryIterator NBLog::FormatEntry::args() const {
     auto it = begin();
     // skip start fmt
     ++it;
     // skip timestamp
     ++it;
+    // skip hash
+    ++it;
     // Skip author if present
     if (it->type == EVENT_AUTHOR) {
         ++it;
@@ -79,19 +175,33 @@
     return it;
 }
 
-timespec NBLog::FormatEntry::timestamp() const {
+int64_t NBLog::FormatEntry::timestamp() const {
     auto it = begin();
     // skip start fmt
     ++it;
-    return it.payload<timespec>();
+    return it.payload<int64_t>();
 }
 
-pid_t NBLog::FormatEntry::author() const {
+NBLog::log_hash_t NBLog::FormatEntry::hash() const {
     auto it = begin();
     // skip start fmt
     ++it;
     // skip timestamp
     ++it;
+    // unaligned 64-bit read not supported
+    log_hash_t hash;
+    memcpy(&hash, it->data, sizeof(hash));
+    return hash;
+}
+
+int NBLog::FormatEntry::author() const {
+    auto it = begin();
+    // skip start fmt
+    ++it;
+    // skip timestamp
+    ++it;
+    // skip hash
+    ++it;
     // if there is an author entry, return it, return -1 otherwise
     if (it->type == EVENT_AUTHOR) {
         return it.payload<int>();
@@ -99,12 +209,13 @@
     return -1;
 }
 
-NBLog::FormatEntry::iterator NBLog::FormatEntry::copyWithAuthor(
+NBLog::EntryIterator NBLog::FormatEntry::copyWithAuthor(
         std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
     auto it = begin();
     // copy fmt start entry
     it.copyTo(dst);
     // copy timestamp
+    (++it).copyTo(dst);    // copy hash
     (++it).copyTo(dst);
     // insert author entry
     size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author);
@@ -124,71 +235,103 @@
     return it;
 }
 
-void NBLog::FormatEntry::iterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
+void NBLog::EntryIterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
     size_t length = ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
     dst->write(ptr, length);
 }
 
-void NBLog::FormatEntry::iterator::copyData(uint8_t *dst) const {
+void NBLog::EntryIterator::copyData(uint8_t *dst) const {
     memcpy((void*) dst, ptr + offsetof(entry, data), ptr[offsetof(entry, length)]);
 }
 
-NBLog::FormatEntry::iterator NBLog::FormatEntry::begin() const {
-    return iterator(mEntry);
-}
-
-NBLog::FormatEntry::iterator::iterator()
+NBLog::EntryIterator::EntryIterator()
     : ptr(nullptr) {}
 
-NBLog::FormatEntry::iterator::iterator(const uint8_t *entry)
+NBLog::EntryIterator::EntryIterator(const uint8_t *entry)
     : ptr(entry) {}
 
-NBLog::FormatEntry::iterator::iterator(const NBLog::FormatEntry::iterator &other)
+NBLog::EntryIterator::EntryIterator(const NBLog::EntryIterator &other)
     : ptr(other.ptr) {}
 
-const NBLog::FormatEntry::entry& NBLog::FormatEntry::iterator::operator*() const {
+const NBLog::entry& NBLog::EntryIterator::operator*() const {
     return *(entry*) ptr;
 }
 
-const NBLog::FormatEntry::entry* NBLog::FormatEntry::iterator::operator->() const {
+const NBLog::entry* NBLog::EntryIterator::operator->() const {
     return (entry*) ptr;
 }
 
-NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator++() {
+NBLog::EntryIterator& NBLog::EntryIterator::operator++() {
     ptr += ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
     return *this;
 }
 
-NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator--() {
+NBLog::EntryIterator& NBLog::EntryIterator::operator--() {
     ptr -= ptr[NBLog::Entry::kPreviousLengthOffset] + NBLog::Entry::kOverhead;
     return *this;
 }
 
-NBLog::FormatEntry::iterator NBLog::FormatEntry::iterator::next() const {
-    iterator aux(*this);
+NBLog::EntryIterator NBLog::EntryIterator::next() const {
+    EntryIterator aux(*this);
     return ++aux;
 }
 
-NBLog::FormatEntry::iterator NBLog::FormatEntry::iterator::prev() const {
-    iterator aux(*this);
+NBLog::EntryIterator NBLog::EntryIterator::prev() const {
+    EntryIterator aux(*this);
     return --aux;
 }
 
-int NBLog::FormatEntry::iterator::operator-(const NBLog::FormatEntry::iterator &other) const {
+int NBLog::EntryIterator::operator-(const NBLog::EntryIterator &other) const {
     return ptr - other.ptr;
 }
 
-bool NBLog::FormatEntry::iterator::operator!=(const iterator &other) const {
+bool NBLog::EntryIterator::operator!=(const EntryIterator &other) const {
     return ptr != other.ptr;
 }
 
-bool NBLog::FormatEntry::iterator::hasConsistentLength() const {
+bool NBLog::EntryIterator::hasConsistentLength() const {
     return ptr[offsetof(entry, length)] == ptr[ptr[offsetof(entry, length)] +
         NBLog::Entry::kOverhead + NBLog::Entry::kPreviousLengthOffset];
 }
 
 // ---------------------------------------------------------------------------
 
+int64_t NBLog::HistogramEntry::timestamp() const {
+    return EntryIterator(mEntry).payload<HistTsEntry>().ts;
+}
+
+NBLog::log_hash_t NBLog::HistogramEntry::hash() const {
+    return EntryIterator(mEntry).payload<HistTsEntry>().hash;
+}
+
+int NBLog::HistogramEntry::author() const {
+    EntryIterator it(mEntry);
+    if (it->length == sizeof(HistTsEntryWithAuthor)) {
+        return it.payload<HistTsEntryWithAuthor>().author;
+    } else {
+        return -1;
+    }
+}
+
+NBLog::EntryIterator NBLog::HistogramEntry::copyWithAuthor(
+        std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
+    // Current histogram entry has {type, length, struct HistTsEntry, length}.
+    // We now want {type, length, struct HistTsEntryWithAuthor, length}
+    uint8_t buffer[Entry::kOverhead + sizeof(HistTsEntryWithAuthor)];
+    // Copy content until the point we want to add the author
+    memcpy(buffer, mEntry, sizeof(entry) + sizeof(HistTsEntry));
+    // Copy the author
+    *(int*) (buffer + sizeof(entry) + sizeof(HistTsEntry)) = author;
+    // Update lengths
+    buffer[offsetof(entry, length)] = sizeof(HistTsEntryWithAuthor);
+    buffer[sizeof(buffer) + Entry::kPreviousLengthOffset] = sizeof(HistTsEntryWithAuthor);
+    // Write new buffer into FIFO
+    dst->write(buffer, sizeof(buffer));
+    return EntryIterator(mEntry).next();
+}
+
+// ---------------------------------------------------------------------------
+
 #if 0   // FIXME see note in NBLog.h
 NBLog::Timeline::Timeline(size_t size, void *shared)
     : mSize(roundup(size)), mOwn(shared == NULL),
@@ -301,13 +444,15 @@
     if (!mEnabled) {
         return;
     }
-    struct timespec ts;
-    if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
+    int64_t ts = get_monotonic_ns();
+    if (ts > 0) {
         log(EVENT_TIMESTAMP, &ts, sizeof(ts));
+    } else {
+        ALOGE("Failed to get timestamp");
     }
 }
 
-void NBLog::Writer::logTimestamp(const struct timespec &ts)
+void NBLog::Writer::logTimestamp(const int64_t ts)
 {
     if (!mEnabled) {
         return;
@@ -360,19 +505,57 @@
     log(&entry, true);
 }
 
-void NBLog::Writer::logFormat(const char *fmt, ...)
+void NBLog::Writer::logHash(log_hash_t hash)
+{
+    if (!mEnabled) {
+        return;
+    }
+    log(EVENT_HASH, &hash, sizeof(hash));
+}
+
+void NBLog::Writer::logHistTS(log_hash_t hash)
+{
+    if (!mEnabled) {
+        return;
+    }
+    HistTsEntry data;
+    data.hash = hash;
+    data.ts = get_monotonic_ns();
+    if (data.ts > 0) {
+        log(EVENT_HISTOGRAM_ENTRY_TS, &data, sizeof(data));
+    } else {
+        ALOGE("Failed to get timestamp");
+    }
+}
+
+void NBLog::Writer::logHistFlush(log_hash_t hash)
+{
+    if (!mEnabled) {
+        return;
+    }
+    HistTsEntry data;
+    data.hash = hash;
+    data.ts = get_monotonic_ns();
+    if (data.ts > 0) {
+        log(EVENT_HISTOGRAM_FLUSH, &data, sizeof(data));
+    } else {
+        ALOGE("Failed to get timestamp");
+    }
+}
+
+void NBLog::Writer::logFormat(const char *fmt, log_hash_t hash, ...)
 {
     if (!mEnabled) {
         return;
     }
 
     va_list ap;
-    va_start(ap, fmt);
-    Writer::logVFormat(fmt, ap);
+    va_start(ap, hash);
+    Writer::logVFormat(fmt, hash, ap);
     va_end(ap);
 }
 
-void NBLog::Writer::logVFormat(const char *fmt, va_list argp)
+void NBLog::Writer::logVFormat(const char *fmt, log_hash_t hash, va_list argp)
 {
     if (!mEnabled) {
         return;
@@ -381,8 +564,9 @@
     int i;
     double f;
     char* s;
-    struct timespec t;
+    int64_t t;
     Writer::logTimestamp();
+    Writer::logHash(hash);
     for (const char *p = fmt; *p != '\0'; p++) {
         // TODO: implement more complex formatting such as %.3f
         if (*p != '%') {
@@ -395,7 +579,7 @@
             break;
 
         case 't': // timestamp
-            t = va_arg(argp, struct timespec);
+            t = va_arg(argp, int64_t);
             Writer::logTimestamp(t);
             break;
 
@@ -440,40 +624,35 @@
         //      a confusion for a programmer debugging their code.
         return;
     }
-    switch (event) {
-    case EVENT_STRING:
-    case EVENT_TIMESTAMP:
-    case EVENT_INTEGER:
-    case EVENT_FLOAT:
-    case EVENT_PID:
-    case EVENT_START_FMT:
-        break;
-    case EVENT_RESERVED:
-    default:
+    // Ignore if invalid event
+    if (event == EVENT_RESERVED || event >= EVENT_UPPER_BOUND) {
         return;
     }
-    Entry entry(event, data, length);
-    log(&entry, true /*trusted*/);
+    Entry etr(event, data, length);
+    log(&etr, true /*trusted*/);
 }
 
-void NBLog::Writer::log(const NBLog::Entry *entry, bool trusted)
+void NBLog::Writer::log(const NBLog::Entry *etr, bool trusted)
 {
     if (!mEnabled) {
         return;
     }
     if (!trusted) {
-        log(entry->mEvent, entry->mData, entry->mLength);
+        log(etr->mEvent, etr->mData, etr->mLength);
         return;
     }
-    size_t need = entry->mLength + Entry::kOverhead;    // mEvent, mLength, data[length], mLength
-                                                        // need = number of bytes remaining to write
+    size_t need = etr->mLength + Entry::kOverhead;    // mEvent, mLength, data[mLength], mLength
+                                                      // need = number of bytes written to FIFO
 
     // FIXME optimize this using memcpy for the data part of the Entry.
     // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
+    // checks size of a single log Entry: type, length, data pointer and ending
     uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
+    // write this data to temp array
     for (size_t i = 0; i < need; i++) {
-        temp[i] = entry->readAt(i);
+        temp[i] = etr->copyEntryDataAt(i);
     }
+    // write to circular buffer
     mFifoWriter->write(temp, need);
 }
 
@@ -531,7 +710,7 @@
     Writer::logTimestamp();
 }
 
-void NBLog::LockedWriter::logTimestamp(const struct timespec &ts)
+void NBLog::LockedWriter::logTimestamp(const int64_t ts)
 {
     Mutex::Autolock _l(mLock);
     Writer::logTimestamp(ts);
@@ -568,6 +747,12 @@
     Writer::logEnd();
 }
 
+void NBLog::LockedWriter::logHash(log_hash_t hash)
+{
+    Mutex::Autolock _l(mLock);
+    Writer::logHash(hash);
+}
+
 bool NBLog::LockedWriter::isEnabled() const
 {
     Mutex::Autolock _l(mLock);
@@ -582,13 +767,19 @@
 
 // ---------------------------------------------------------------------------
 
+const std::set<NBLog::Event> NBLog::Reader::startingTypes {NBLog::Event::EVENT_START_FMT,
+                                                           NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS};
+const std::set<NBLog::Event> NBLog::Reader::endingTypes   {NBLog::Event::EVENT_END_FMT,
+                                                           NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
+                                                           NBLog::Event::EVENT_HISTOGRAM_FLUSH};
 NBLog::Reader::Reader(const void *shared, size_t size)
     : mShared((/*const*/ Shared *) shared), /*mIMemory*/
       mFd(-1), mIndent(0),
       mFifo(mShared != NULL ?
         new audio_utils_fifo(size, sizeof(uint8_t),
             mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
-      mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
+      mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL),
+      findGlitch(false)
 {
 }
 
@@ -604,16 +795,50 @@
     delete mFifo;
 }
 
-uint8_t *NBLog::Reader::findLastEntryOfType(uint8_t *front, uint8_t *back, uint8_t type) {
+inline static int deltaMs(int64_t ns1, int64_t ns2) {
+    return (ns2 - ns1) / (1000 * 1000);
+}
+
+// Produces a log warning if the timing of recent buffer periods caused a glitch
+// Computes sum of running window of three buffer periods
+// Checks whether the buffer periods leave enough CPU time for the next one
+// e.g. if a buffer period is expected to be 4 ms and a buffer requires 3 ms of CPU time,
+// here are some glitch cases:
+// 4 + 4 + 6 ; 5 + 4 + 5; 2 + 2 + 10
+// TODO: develop this code to track changes in histogram distribution in addition
+// to / instead of glitches
+void NBLog::Reader::alertIfGlitch(const std::vector<int64_t> &samples) {
+    //TODO: measure kPeriodLen and kRatio from the data as they may change.
+    static const int kPeriodLen = 4; // current period length is ideally 4 ms
+    static const double kRatio = 0.75; // estimate of CPU time as ratio of period length
+    // DAC processing time for 4 ms buffer
+    static const int kPeriodTime = static_cast<int>(round(kPeriodLen * kRatio));
+    static const int kNumBuff = 3; // number of buffers considered in local history
+    std::deque<int> periods(kNumBuff, kPeriodLen);
+    for (size_t i = 2; i < samples.size(); ++i) { // skip first time entry
+        periods.push_front(deltaMs(samples[i - 1], samples[i]));
+        periods.pop_back();
+        // TODO: check that all glitch cases are covered
+        if (std::accumulate(periods.begin(), periods.end(), 0) > kNumBuff * kPeriodLen +
+            kPeriodLen - kPeriodTime) {
+                ALOGW("A glitch occurred");
+                periods.assign(kNumBuff, kPeriodLen);
+        }
+    }
+    return;
+}
+
+const uint8_t *NBLog::Reader::findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
+                                            const std::set<Event> &types) {
     while (back + Entry::kPreviousLengthOffset >= front) {
-        uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead;
-        if (prev < front || prev + prev[offsetof(FormatEntry::entry, length)] +
+        const uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead;
+        if (prev < front || prev + prev[offsetof(entry, length)] +
                             Entry::kOverhead != back) {
 
             // prev points to an out of limits or inconsistent entry
             return nullptr;
         }
-        if (prev[offsetof(FormatEntry::entry, type)] == type) {
+        if (types.find((const Event) prev[offsetof(entry, type)]) != types.end()) {
             return prev;
         }
         back = prev;
@@ -652,21 +877,21 @@
     // it ends in a complete entry (which is not an END_FMT). So is safe to traverse backwards.
     // TODO: handle client corruption (in the middle of a buffer)
 
-    uint8_t *back = snapshot->mData + availToRead;
-    uint8_t *front = snapshot->mData;
+    const uint8_t *back = snapshot->mData + availToRead;
+    const uint8_t *front = snapshot->mData;
 
     // Find last END_FMT. <back> is sitting on an entry which might be the middle of a FormatEntry.
     // We go backwards until we find an EVENT_END_FMT.
-    uint8_t *lastEnd = findLastEntryOfType(front, back, EVENT_END_FMT);
+    const uint8_t *lastEnd = findLastEntryOfTypes(front, back, endingTypes);
     if (lastEnd == nullptr) {
-        snapshot->mEnd = snapshot->mBegin = FormatEntry::iterator(front);
+        snapshot->mEnd = snapshot->mBegin = EntryIterator(front);
     } else {
         // end of snapshot points to after last END_FMT entry
-        snapshot->mEnd = FormatEntry::iterator(lastEnd + Entry::kOverhead);
+        snapshot->mEnd = EntryIterator(lastEnd).next();
         // find first START_FMT
-        uint8_t *firstStart = nullptr;
-        uint8_t *firstStartTmp = lastEnd;
-        while ((firstStartTmp = findLastEntryOfType(front, firstStartTmp, EVENT_START_FMT))
+        const uint8_t *firstStart = nullptr;
+        const uint8_t *firstStartTmp = snapshot->mEnd;
+        while ((firstStartTmp = findLastEntryOfTypes(front, firstStartTmp, startingTypes))
                 != nullptr) {
             firstStart = firstStartTmp;
         }
@@ -674,7 +899,7 @@
         if (firstStart == nullptr) {
             snapshot->mBegin = snapshot->mEnd;
         } else {
-            snapshot->mBegin = FormatEntry::iterator(firstStart);
+            snapshot->mBegin = EntryIterator(firstStart);
         }
     }
 
@@ -686,8 +911,37 @@
 
 }
 
+// writes sample deltas to file, either truncating or appending
+inline void writeHistToFile(const std::vector<int64_t> &samples, bool append) {
+    // name of file on audioserver
+    static const char* const kName = (char *)"/data/misc/audioserver/sample_results.txt";
+    // stores deltas between the samples
+    std::vector<int64_t> intervals;
+    if (samples.size() == 0) return;
+    for (size_t i = 1; i < samples.size(); ++i) {
+        intervals.push_back(deltaMs(samples[i - 1], samples[i]));
+    }
+    // Deletes maximum value in a histogram. Temp quick fix.
+    // FIXME: need to find root cause of approx. 35th element from the end
+    // consistently being an outlier in the first histogram of a flush
+    // ALOGW("%" PRId64 "before", (int64_t) *(std::max_element(intervals.begin(), intervals.end())));
+    intervals.erase(std::max_element(intervals.begin(), intervals.end()));
+    // ALOGW("%" PRId64 "after", (int64_t) *(std::max_element(intervals.begin(), intervals.end())));
+    std::ofstream ofs;
+    ofs.open(kName, append ? std::ios::app : std::ios::trunc);
+    if (!ofs) {
+        ALOGW("couldn't open file %s", kName);
+        return;
+    }
+    for (size_t i = 0; i < intervals.size(); ++i) {
+        ofs << intervals[i] << "\n";
+    }
+    ofs.close();
+}
+
 void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot)
 {
+  //  CallStack cs(LOG_TAG);
 #if 0
     struct timespec ts;
     time_t maxSec = -1;
@@ -712,11 +966,11 @@
     mFd = fd;
     mIndent = indent;
     String8 timestamp, body;
-    size_t lost = snapshot.lost() + (snapshot.begin() - FormatEntry::iterator(snapshot.data()));
+    size_t lost = snapshot.lost() + (snapshot.begin() - EntryIterator(snapshot.data()));
     if (lost > 0) {
         body.appendFormat("warning: lost %zu bytes worth of events", lost);
         // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
-        //      log to push it out.  Consider keeping the timestamp/body between calls to readAt().
+        //      log to push it out.  Consider keeping the timestamp/body between calls to copyEntryDataAt().
         dumpLine(timestamp, body);
     }
 #if 0
@@ -730,6 +984,7 @@
     }
     bool deferredTimestamp = false;
 #endif
+
     for (auto entry = snapshot.begin(); entry != snapshot.end();) {
         switch (entry->type) {
 #if 0
@@ -798,9 +1053,53 @@
             break;
 #endif
         case EVENT_START_FMT:
-            // right now, this is the only supported case
             entry = handleFormat(FormatEntry(entry), &timestamp, &body);
             break;
+        case EVENT_HISTOGRAM_ENTRY_TS: {
+            HistTsEntryWithAuthor *data = (HistTsEntryWithAuthor *) (entry->data);
+            // TODO This memcpies are here to avoid unaligned memory access crash.
+            // There's probably a more efficient way to do it
+            log_hash_t hash;
+            memcpy(&hash, &(data->hash), sizeof(hash));
+            int64_t ts;
+            memcpy(&ts, &data->ts, sizeof(ts));
+            const std::pair<log_hash_t, int> key(hash, data->author);
+            // TODO might want to filter excessively high outliers, which are usually caused
+            // by the thread being inactive.
+            mHists[key].push_back(ts);
+            ++entry;
+            break;
+        }
+        // draws histograms stored in global Reader::mHists and erases them
+        case EVENT_HISTOGRAM_FLUSH: {
+            HistogramEntry histEntry(entry);
+            // Log timestamp
+            // Timestamp of call to drawHistogram, not when audio was generated
+            const int64_t ts = histEntry.timestamp();
+            timestamp.clear();
+            timestamp.appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
+                            (int) ((ts / (1000 * 1000)) % 1000));
+            // Log histograms
+            setFindGlitch(true);
+            body.appendFormat("Histogram flush - ");
+            handleAuthor(histEntry, &body);
+            for (auto hist = mHists.begin(); hist != mHists.end();) {
+                if (hist->first.second == histEntry.author()) {
+                    body.appendFormat("%X", (int)hist->first.first);
+                    if (findGlitch) {
+                        alertIfGlitch(hist->second);
+                    }
+                    // set file to empty and write data for all histograms in this set
+                    writeHistToFile(hist->second, hist != mHists.begin());
+                    drawHistogram(&body, hist->second, true, indent);
+                    hist = mHists.erase(hist);
+                } else {
+                    ++hist;
+                }
+            }
+            ++entry;
+            break;
+        }
         case EVENT_END_FMT:
             body.appendFormat("warning: got to end format event");
             ++entry;
@@ -814,12 +1113,8 @@
 
         if (!body.isEmpty()) {
             dumpLine(timestamp, body);
-            // deferredTimestamp = false;
         }
     }
-    // if (deferredTimestamp) {
-    //     dumpLine(timestamp, body);
-    // }
 }
 
 void NBLog::Reader::dump(int fd, size_t indent)
@@ -844,11 +1139,23 @@
     return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
 }
 
+void NBLog::Reader::setFindGlitch(bool s)
+{
+    findGlitch = s;
+}
+
+bool NBLog::Reader::isFindGlitch() const
+{
+    return findGlitch;
+}
+
+// ---------------------------------------------------------------------------
+
 void NBLog::appendTimestamp(String8 *body, const void *data) {
-    struct timespec ts;
-    memcpy(&ts, data, sizeof(struct timespec));
-    body->appendFormat("[%d.%03d]", (int) ts.tv_sec,
-                    (int) (ts.tv_nsec / 1000000));
+    int64_t ts;
+    memcpy(&ts, data, sizeof(ts));
+    body->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
+                    (int) ((ts / (1000 * 1000)) % 1000));
 }
 
 void NBLog::appendInt(String8 *body, const void *data) {
@@ -868,20 +1175,42 @@
     body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
 }
 
-NBLog::FormatEntry::iterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry,
+String8 NBLog::bufferDump(const uint8_t *buffer, size_t size)
+{
+    String8 str;
+    str.append("[ ");
+    for(size_t i = 0; i < size; i++)
+    {
+        str.appendFormat("%d ", buffer[i]);
+    }
+    str.append("]");
+    return str;
+}
+
+String8 NBLog::bufferDump(const EntryIterator &it)
+{
+    return bufferDump(it, it->length + Entry::kOverhead);
+}
+
+NBLog::EntryIterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry,
                                                          String8 *timestamp,
                                                          String8 *body) {
     // log timestamp
-    struct timespec ts = fmtEntry.timestamp();
+    int64_t ts = fmtEntry.timestamp();
     timestamp->clear();
-    timestamp->appendFormat("[%d.%03d]", (int) ts.tv_sec,
-                    (int) (ts.tv_nsec / 1000000));
+    timestamp->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
+                    (int) ((ts / (1000 * 1000)) % 1000));
+
+    // log unique hash
+    log_hash_t hash = fmtEntry.hash();
+    // print only lower 16bit of hash as hex and line as int to reduce spam in the log
+    body->appendFormat("%.4X-%d ", (int)(hash >> 16) & 0xFFFF, (int) hash & 0xFFFF);
 
     // log author (if present)
     handleAuthor(fmtEntry, body);
 
     // log string
-    NBLog::FormatEntry::iterator arg = fmtEntry.args();
+    NBLog::EntryIterator arg = fmtEntry.args();
 
     const char* fmt = fmtEntry.formatString();
     size_t fmt_length = fmtEntry.formatStringLength();
@@ -954,7 +1283,125 @@
     return arg;
 }
 
-// ---------------------------------------------------------------------------
+static int widthOf(int x) {
+    int width = 0;
+    while (x > 0) {
+        ++width;
+        x /= 10;
+    }
+    return width;
+}
+
+static std::map<int, int> buildBuckets(const std::vector<int64_t> &samples) {
+    // TODO allow buckets of variable resolution
+    std::map<int, int> buckets;
+    for (size_t i = 1; i < samples.size(); ++i) {
+        ++buckets[deltaMs(samples[i - 1], samples[i])];
+    }
+    return buckets;
+}
+
+static inline uint32_t log2(uint32_t x) {
+    // This works for x > 0
+    return 31 - __builtin_clz(x);
+}
+
+// TODO put this function in separate file. Make it return a std::string instead of modifying body
+/*
+Example output:
+[54.234] Histogram flush - AudioOut_D:
+Histogram 33640BF1
+            [ 1][ 1][ 1][ 3][54][69][ 1][ 2][ 1]
+        64|                      []
+        32|                  []  []
+        16|                  []  []
+         8|                  []  []
+         4|                  []  []
+         2|______________[]__[]__[]______[]____
+              4   5   6   8   9  10  11  13  15
+Notice that all values that fall in the same row have the same height (65 and 127 are displayed
+identically). That's why exact counts are added at the top.
+*/
+void NBLog::Reader::drawHistogram(String8 *body,
+                                  const std::vector<int64_t> &samples,
+                                  bool logScale,
+                                  int indent,
+                                  int maxHeight) {
+    // this avoids some corner cases
+    if (samples.size() <= 1) {
+        return;
+    }
+    // temp code for debugging the outlier timestamp
+    const int kMaxMs = 100;
+    for (size_t i = 1; i < samples.size()-1; ++i) {
+        const int currDelta = deltaMs(samples[i - 1], samples[i]);
+        if (currDelta > kMaxMs) {
+            body->appendFormat("\nlocation: %zu, size: %zu, pos from end: %zu, %d\t", i,
+                           samples.size(), samples.size() - i, currDelta);
+        }
+    }
+    // FIXME: as can be seen when printing the values, the outlier timestamps typically occur
+    // in the first histogram 35 to 38 indices from the end (most often 35).
+    // TODO: build histogram buckets earlier and discard timestamps to save memory
+    std::map<int, int> buckets = buildBuckets(samples);
+    // TODO consider changing all ints to uint32_t or uint64_t
+
+    // underscores and spaces length corresponds to maximum width of histogram
+    static const int kLen = 40;
+    std::string underscores(kLen, '-');
+    std::string spaces(kLen, ' ');
+
+    auto it = buckets.begin();
+    int maxDelta = it->first;
+    int maxCount = it->second;
+    // Compute maximum values
+    while (++it != buckets.end()) {
+        if (it->first > maxDelta) {
+            maxDelta = it->first;
+        }
+        if (it->second > maxCount) {
+            maxCount = it->second;
+        }
+    }
+    int height = logScale ? log2(maxCount) + 1 : maxCount; // maxCount > 0, safe to call log2
+    const int leftPadding = widthOf(logScale ? pow(2, height) : maxCount);
+    const int colWidth = std::max(std::max(widthOf(maxDelta) + 1, 3), leftPadding + 2);
+    int scalingFactor = 1;
+    // scale data if it exceeds maximum height
+    if (height > maxHeight) {
+        scalingFactor = (height + maxHeight) / maxHeight;
+        height /= scalingFactor;
+    }
+    body->appendFormat("\n%*s", leftPadding + 11, "Occurrences");
+    // write histogram label line with bucket values
+    body->appendFormat("\n%*s", indent, " ");
+    body->appendFormat("%*s", leftPadding, " ");
+    for (auto const &x : buckets) {
+        body->appendFormat("%*d", colWidth, x.second);
+    }
+    // write histogram ascii art
+    body->appendFormat("\n%*s", indent, " ");
+    for (int row = height * scalingFactor; row >= 0; row -= scalingFactor) {
+        const int value = logScale ? (1 << row) : row;
+        body->appendFormat("%.*s", leftPadding, spaces.c_str());
+        for (auto const &x : buckets) {
+          body->appendFormat("%.*s%s", colWidth - 1, spaces.c_str(), x.second < value ? " " : "|");
+        }
+        body->appendFormat("\n%*s", indent, " ");
+    }
+    // print x-axis
+    const int columns = static_cast<int>(buckets.size());
+    body->appendFormat("%*c", leftPadding, ' ');
+    body->appendFormat("%.*s", (columns + 1) * colWidth, underscores.c_str());
+    body->appendFormat("\n%*s", indent, " ");
+
+    // write footer with bucket labels
+    body->appendFormat("%*s", leftPadding, " ");
+    for (auto const &x : buckets) {
+        body->appendFormat("%*d", colWidth, x.first);
+    }
+    body->appendFormat("%.*s%s", colWidth, spaces.c_str(), "ms\n");
+}
 
 NBLog::Merger::Merger(const void *shared, size_t size):
       mShared((Shared *) shared),
@@ -965,6 +1412,8 @@
       {}
 
 void NBLog::Merger::addReader(const NBLog::NamedReader &reader) {
+    // FIXME This is called by binder thread in MediaLogService::registerWriter
+    //       but the access to shared variable mNamedReaders is not yet protected by a lock.
     mNamedReaders.push_back(reader);
 }
 
@@ -972,26 +1421,27 @@
 // composed by a timestamp and the index of the snapshot where the timestamp came from
 struct MergeItem
 {
-    struct timespec ts;
+    int64_t ts;
     int index;
-    MergeItem(struct timespec ts, int index): ts(ts), index(index) {}
+    MergeItem(int64_t ts, int index): ts(ts), index(index) {}
 };
 
 // operators needed for priority queue in merge
-bool operator>(const struct timespec &t1, const struct timespec &t2) {
-    return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec);
-}
+// bool operator>(const int64_t &t1, const int64_t &t2) {
+//     return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec);
+// }
 
 bool operator>(const struct MergeItem &i1, const struct MergeItem &i2) {
-    return i1.ts > i2.ts ||
-        (i1.ts.tv_sec == i2.ts.tv_sec && i1.ts.tv_nsec == i2.ts.tv_nsec && i1.index > i2.index);
+    return i1.ts > i2.ts || (i1.ts == i2.ts && i1.index > i2.index);
 }
 
 // Merge registered readers, sorted by timestamp
 void NBLog::Merger::merge() {
+    // FIXME This is called by merge thread
+    //       but the access to shared variable mNamedReaders is not yet protected by a lock.
     int nLogs = mNamedReaders.size();
     std::vector<std::unique_ptr<NBLog::Reader::Snapshot>> snapshots(nLogs);
-    std::vector<NBLog::FormatEntry::iterator> offsets(nLogs);
+    std::vector<NBLog::EntryIterator> offsets(nLogs);
     for (int i = 0; i < nLogs; ++i) {
         snapshots[i] = mNamedReaders[i].reader()->getSnapshot();
         offsets[i] = snapshots[i]->begin();
@@ -1003,7 +1453,7 @@
     for (int i = 0; i < nLogs; ++i)
     {
         if (offsets[i] != snapshots[i]->end()) {
-            timespec ts = FormatEntry(offsets[i]).timestamp();
+            int64_t ts = AbstractEntry::buildEntry(offsets[i])->timestamp();
             timestamps.emplace(ts, i);
         }
     }
@@ -1012,30 +1462,36 @@
         // find minimum timestamp
         int index = timestamps.top().index;
         // copy it to the log, increasing offset
-        offsets[index] = FormatEntry(offsets[index]).copyWithAuthor(mFifoWriter, index);
+        offsets[index] = AbstractEntry::buildEntry(offsets[index])->copyWithAuthor(mFifoWriter,
+                                                                                   index);
         // update data structures
         timestamps.pop();
         if (offsets[index] != snapshots[index]->end()) {
-            timespec ts = FormatEntry(offsets[index]).timestamp();
+            int64_t ts = AbstractEntry::buildEntry(offsets[index])->timestamp();
             timestamps.emplace(ts, index);
         }
     }
 }
 
-const std::vector<NBLog::NamedReader> *NBLog::Merger::getNamedReaders() const {
-    return &mNamedReaders;
+const std::vector<NBLog::NamedReader>& NBLog::Merger::getNamedReaders() const {
+    // FIXME This is returning a reference to a shared variable that needs a lock
+    return mNamedReaders;
 }
 
+// ---------------------------------------------------------------------------
+
 NBLog::MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
     : Reader(shared, size), mNamedReaders(merger.getNamedReaders()) {}
 
-size_t NBLog::MergeReader::handleAuthor(const NBLog::FormatEntry &fmtEntry, String8 *body) {
-    int author = fmtEntry.author();
-    const char* name = (*mNamedReaders)[author].name();
+void NBLog::MergeReader::handleAuthor(const NBLog::AbstractEntry &entry, String8 *body) {
+    int author = entry.author();
+    // FIXME Needs a lock
+    const char* name = mNamedReaders[author].name();
     body->appendFormat("%s: ", name);
-    return NBLog::Entry::kOverhead + sizeof(author);
 }
 
+// ---------------------------------------------------------------------------
+
 NBLog::MergeThread::MergeThread(NBLog::Merger &merger)
     : mMerger(merger),
       mTimeoutUs(0) {}
diff --git a/media/libnbaio/include/NBLog.h b/media/libnbaio/include/NBLog.h
index bcebe9e..785b9c2 100644
--- a/media/libnbaio/include/NBLog.h
+++ b/media/libnbaio/include/NBLog.h
@@ -24,6 +24,8 @@
 #include <utils/Mutex.h>
 #include <utils/threads.h>
 
+#include <map>
+#include <set>
 #include <vector>
 
 namespace android {
@@ -34,12 +36,16 @@
 
 public:
 
+typedef uint64_t log_hash_t;
+
+// FIXME Everything needed for client (writer API and registration) should be isolated
+//       from the rest of the implementation.
 class Writer;
 class Reader;
 
 private:
 
-enum Event {
+enum Event : uint8_t {
     EVENT_RESERVED,
     EVENT_STRING,               // ASCII string, not NUL-terminated
     // TODO: make timestamp optional
@@ -50,7 +56,13 @@
     EVENT_AUTHOR,               // author index (present in merged logs) tracks entry's original log
     EVENT_START_FMT,            // logFormat start event: entry includes format string, following
                                 // entries contain format arguments
+    EVENT_HASH,                 // unique HASH of log origin, originates from hash of file name
+                                // and line number
+    EVENT_HISTOGRAM_ENTRY_TS,   // single datum for timestamp histogram
+    EVENT_HISTOGRAM_FLUSH,      // show histogram on log
     EVENT_END_FMT,              // end of logFormat argument list
+
+    EVENT_UPPER_BOUND,          // to check for invalid events
 };
 
 
@@ -60,94 +72,146 @@
 // a formatted entry has the following structure:
 //    * START_FMT entry, containing the format string
 //    * TIMESTAMP entry
+//    * HASH entry
 //    * author entry of the thread that generated it (optional, present in merged log)
 //    * format arg1
 //    * format arg2
 //    * ...
 //    * END_FMT entry
 
-class FormatEntry {
+// entry representation in memory
+struct entry {
+    const uint8_t type;
+    const uint8_t length;
+    const uint8_t data[0];
+};
+
+// entry tail representation (after data)
+struct ending {
+    uint8_t length;
+    uint8_t next[0];
+};
+
+// entry iterator
+class EntryIterator {
 public:
-    // build a Format Entry starting in the given pointer
-    class iterator;
-    explicit FormatEntry(const uint8_t *entry);
-    explicit FormatEntry(const iterator &it);
-    virtual ~FormatEntry() {}
+    EntryIterator();
+    explicit EntryIterator(const uint8_t *entry);
+    EntryIterator(const EntryIterator &other);
 
-    // entry representation in memory
-    struct entry {
-        const uint8_t type;
-        const uint8_t length;
-        const uint8_t data[0];
-    };
+    // dereference underlying entry
+    const entry&    operator*() const;
+    const entry*    operator->() const;
+    // advance to next entry
+    EntryIterator&       operator++(); // ++i
+    // back to previous entry
+    EntryIterator&       operator--(); // --i
+    EntryIterator        next() const;
+    EntryIterator        prev() const;
+    bool            operator!=(const EntryIterator &other) const;
+    int             operator-(const EntryIterator &other) const;
 
-    // entry tail representation (after data)
-    struct ending {
-        uint8_t length;
-        uint8_t next[0];
-    };
+    bool            hasConsistentLength() const;
+    void            copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
+    void            copyData(uint8_t *dst) const;
 
-    // entry iterator
-    class iterator {
-    public:
-        iterator();
-        iterator(const uint8_t *entry);
-        iterator(const iterator &other);
+    template<typename T>
+    inline const T& payload() {
+        return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
+    }
 
-        // dereference underlying entry
-        const entry&    operator*() const;
-        const entry*    operator->() const;
-        // advance to next entry
-        iterator&       operator++(); // ++i
-        // back to previous entry
-        iterator&       operator--(); // --i
-        iterator        next() const;
-        iterator        prev() const;
-        bool            operator!=(const iterator &other) const;
-        int             operator-(const iterator &other) const;
+    inline operator const uint8_t*() const {
+        return ptr;
+    }
 
-        bool            hasConsistentLength() const;
-        void            copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
-        void            copyData(uint8_t *dst) const;
+private:
+    const uint8_t  *ptr;
+};
 
-        template<typename T>
-        inline const T& payload() {
-            return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
-        }
+class AbstractEntry {
+public:
 
-    private:
-        friend class FormatEntry;
-        const uint8_t  *ptr;
-    };
+    // Entry starting in the given pointer
+    explicit AbstractEntry(const uint8_t *entry);
+    virtual ~AbstractEntry() {}
 
-    // Entry's format string
-    const char* formatString() const;
-
-    // Enrty's format string length
-    size_t      formatStringLength() const;
-
-    // Format arguments (excluding format string, timestamp and author)
-    iterator    args() const;
+    // build concrete entry of appropriate class from pointer
+    static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
 
     // get format entry timestamp
-    timespec    timestamp() const;
+    // TODO consider changing to uint64_t
+    virtual int64_t      timestamp() const = 0;
+
+    // get format entry's unique id
+    virtual log_hash_t   hash() const = 0;
 
     // entry's author index (-1 if none present)
     // a Merger has a vector of Readers, author simply points to the index of the
     // Reader that originated the entry
-    int         author() const;
+    // TODO consider changing to uint32_t
+    virtual int          author() const = 0;
 
-    // copy entry, adding author before timestamp, returns size of original entry
-    iterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const;
+    // copy entry, adding author before timestamp, returns iterator to end of entry
+    virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+                                       int author) const = 0;
 
-    iterator    begin() const;
-
-private:
+protected:
     // copies ordinary entry from src to dst, and returns length of entry
     // size_t      copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
     const uint8_t  *mEntry;
 };
 
+class FormatEntry : public AbstractEntry {
+public:
+    // explicit FormatEntry(const EntryIterator &it);
+    explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
+    virtual ~FormatEntry() {}
+
+    EntryIterator begin() const;
+
+    // Entry's format string
+    const   char* formatString() const;
+
+    // Enrty's format string length
+            size_t      formatStringLength() const;
+
+    // Format arguments (excluding format string, timestamp and author)
+            EntryIterator    args() const;
+
+    // get format entry timestamp
+    virtual int64_t     timestamp() const override;
+
+    // get format entry's unique id
+    virtual log_hash_t  hash() const override;
+
+    // entry's author index (-1 if none present)
+    // a Merger has a vector of Readers, author simply points to the index of the
+    // Reader that originated the entry
+    virtual int         author() const override;
+
+    // copy entry, adding author before timestamp, returns size of original entry
+    virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+                                       int author) const override;
+
+};
+
+class HistogramEntry : public AbstractEntry {
+public:
+    explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {
+    }
+    virtual ~HistogramEntry() {}
+
+    virtual int64_t     timestamp() const override;
+
+    virtual log_hash_t  hash() const override;
+
+    virtual int         author() const override;
+
+    virtual EntryIterator    copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+                                       int author) const override;
+
+};
+
 // ---------------------------------------------------------------------------
 
 // representation of a single log entry in private memory
@@ -156,7 +220,8 @@
         : mEvent(event), mLength(length), mData(data) { }
     /*virtual*/ ~Entry() { }
 
-    int     readAt(size_t offset) const;
+    // used during writing to format Entry information as follows: [type][length][data ... ][length]
+    int     copyEntryDataAt(size_t offset) const;
 
 private:
     friend class Writer;
@@ -166,12 +231,28 @@
     static const size_t kMaxLength = 255;
 public:
     // mEvent, mLength, mData[...], duplicate mLength
-    static const size_t kOverhead = sizeof(FormatEntry::entry) + sizeof(FormatEntry::ending);
+    static const size_t kOverhead = sizeof(entry) + sizeof(ending);
     // endind length of previous entry
-    static const size_t kPreviousLengthOffset = - sizeof(FormatEntry::ending) +
-                                                offsetof(FormatEntry::ending, length);
+    static const size_t kPreviousLengthOffset = - sizeof(ending) +
+                                                offsetof(ending, length);
 };
 
+struct HistTsEntry {
+    log_hash_t hash;
+    int64_t ts;
+}; //TODO __attribute__((packed));
+
+struct HistTsEntryWithAuthor {
+    log_hash_t hash;
+    int64_t ts;
+    int author;
+}; //TODO __attribute__((packed));
+
+struct HistIntEntry {
+    log_hash_t hash;
+    int value;
+}; //TODO __attribute__((packed));
+
 // representation of a single log entry in shared memory
 //  byte[0]             mEvent
 //  byte[1]             mLength
@@ -188,7 +269,8 @@
     static void    appendPID(String8 *body, const void *data, size_t length);
     static void    appendTimestamp(String8 *body, const void *data);
     static size_t  fmtEntryLength(const uint8_t *data);
-
+    static String8 bufferDump(const uint8_t *buffer, size_t size);
+    static String8 bufferDump(const EntryIterator &it);
 public:
 
 // Located in shared memory, must be POD.
@@ -245,19 +327,22 @@
 
     virtual ~Writer();
 
+    // FIXME needs comments, and some should be private
     virtual void    log(const char *string);
     virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
     virtual void    logvf(const char *fmt, va_list ap);
     virtual void    logTimestamp();
-    virtual void    logTimestamp(const struct timespec &ts);
+    virtual void    logTimestamp(const int64_t ts);
     virtual void    logInteger(const int x);
     virtual void    logFloat(const float x);
     virtual void    logPID();
-    virtual void    logFormat(const char *fmt, ...);
-    virtual void    logVFormat(const char *fmt, va_list ap);
+    virtual void    logFormat(const char *fmt, log_hash_t hash, ...);
+    virtual void    logVFormat(const char *fmt, log_hash_t hash, va_list ap);
     virtual void    logStart(const char *fmt);
     virtual void    logEnd();
-
+    virtual void    logHash(log_hash_t hash);
+    virtual void    logHistTS(log_hash_t hash);
+    virtual void    logHistFlush(log_hash_t hash);
 
     virtual bool    isEnabled() const;
 
@@ -270,7 +355,9 @@
 
 private:
     // 0 <= length <= kMaxLength
+    // writes a single Entry to the FIFO
     void    log(Event event, const void *data, size_t length);
+    // checks validity of an event before calling log above this one
     void    log(const Entry *entry, bool trusted = false);
 
     Shared* const   mShared;    // raw pointer to shared memory
@@ -299,12 +386,13 @@
     virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
     virtual void    logvf(const char *fmt, va_list ap);
     virtual void    logTimestamp();
-    virtual void    logTimestamp(const struct timespec &ts);
+    virtual void    logTimestamp(const int64_t ts);
     virtual void    logInteger(const int x);
     virtual void    logFloat(const float x);
     virtual void    logPID();
     virtual void    logStart(const char *fmt);
     virtual void    logEnd();
+    virtual void    logHash(log_hash_t hash);
 
     virtual bool    isEnabled() const;
     virtual bool    setEnabled(bool enabled);
@@ -335,18 +423,17 @@
 
         // iterator to beginning of readable segment of snapshot
         // data between begin and end has valid entries
-        FormatEntry::iterator begin() { return mBegin; }
+        EntryIterator begin() { return mBegin; }
 
         // iterator to end of readable segment of snapshot
-        FormatEntry::iterator end() { return mEnd; }
-
+        EntryIterator end() { return mEnd; }
 
     private:
         friend class Reader;
         uint8_t              *mData;
         size_t                mLost;
-        FormatEntry::iterator mBegin;
-        FormatEntry::iterator mEnd;
+        EntryIterator mBegin;
+        EntryIterator mEnd;
     };
 
     // Input parameter 'size' is the desired size of the timeline in byte units.
@@ -356,15 +443,22 @@
 
     virtual ~Reader();
 
+    void alertIfGlitch(const std::vector<int64_t> &samples);
+
     // get snapshot of readers fifo buffer, effectively consuming the buffer
     std::unique_ptr<Snapshot> getSnapshot();
     // dump a particular snapshot of the reader
     void     dump(int fd, size_t indent, Snapshot & snap);
-    // dump the current content of the reader's buffer
+    // dump the current content of the reader's buffer (call getSnapshot() and previous dump())
     void     dump(int fd, size_t indent = 0);
     bool     isIMemory(const sp<IMemory>& iMemory) const;
+    // if findGlitch is true, log warning when buffer periods caused glitch
+    void     setFindGlitch(bool s);
+    bool     isFindGlitch() const;
 
 private:
+    static const std::set<Event> startingTypes;
+    static const std::set<Event> endingTypes;
     /*const*/ Shared* const mShared;    // raw pointer to shared memory, actually const but not
                                         // declared as const because audio_utils_fifo() constructor
     sp<IMemory> mIMemory;       // ref-counted version, assigned only in constructor
@@ -375,19 +469,33 @@
     audio_utils_fifo_reader * const mFifoReader;    // used to read from FIFO,
                                                     // non-NULL unless constructor fails
 
+    // each pair contains a sequence of timestamps (one histogram's worth)
+    // pair's log_hash_t is the hash of the source code location where the timestamp was taken
+    // pair's int points to the Reader that originated the entry
+    std::map<std::pair<log_hash_t, int>, std::vector<int64_t>> mHists;
+    // TODO: it might be clearer, instead of a direct map from source location to vector of
+    // timestamps, if we instead first mapped from source location to an object that
+    // represented that location. And one_of its fields would be a vector of timestamps.
+    // That would allow us to record other information about the source location beyond timestamps.
     void    dumpLine(const String8& timestamp, String8& body);
 
-    FormatEntry::iterator   handleFormat(const FormatEntry &fmtEntry,
+    EntryIterator   handleFormat(const FormatEntry &fmtEntry,
                                          String8 *timestamp,
                                          String8 *body);
     // dummy method for handling absent author entry
-    virtual size_t handleAuthor(const FormatEntry& /*fmtEntry*/, String8* /*body*/) { return 0; }
+    virtual void handleAuthor(const AbstractEntry& /*fmtEntry*/, String8* /*body*/) {}
+
+    static void drawHistogram(String8 *body, const std::vector<int64_t> &samples,
+                              bool logScale, int indent = 0, int maxHeight = 10);
 
     // Searches for the last entry of type <type> in the range [front, back)
     // back has to be entry-aligned. Returns nullptr if none enconuntered.
-    static uint8_t *findLastEntryOfType(uint8_t *front, uint8_t *back, uint8_t type);
+    static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
+                                         const std::set<Event> &types);
 
     static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
+
+    bool findGlitch; // alert if a local buffer period sequence caused an audio glitch
 };
 
 // Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
@@ -418,26 +526,30 @@
     void addReader(const NamedReader &reader);
     // TODO add removeReader
     void merge();
-    const std::vector<NamedReader> *getNamedReaders() const;
+    // FIXME This is returning a reference to a shared variable that needs a lock
+    const std::vector<NamedReader>& getNamedReaders() const;
 private:
     // vector of the readers the merger is supposed to merge from.
     // every reader reads from a writer's buffer
+    // FIXME Needs to be protected by a lock
     std::vector<NamedReader> mNamedReaders;
+
+    // TODO Need comments on all of these
     Shared * const mShared;
     std::unique_ptr<audio_utils_fifo> mFifo;
     std::unique_ptr<audio_utils_fifo_writer> mFifoWriter;
-
-    static struct timespec getTimestamp(const uint8_t *data);
 };
 
 class MergeReader : public Reader {
 public:
     MergeReader(const void *shared, size_t size, Merger &merger);
 private:
-    const std::vector<NamedReader> *mNamedReaders;
+    // FIXME Needs to be protected by a lock,
+    //       because even though our use of it is read-only there may be asynchronous updates
+    const std::vector<NamedReader>& mNamedReaders;
     // handle author entry by looking up the author's name and appending it to the body
     // returns number of bytes read from fmtEntry
-    size_t handleAuthor(const FormatEntry &fmtEntry, String8 *body);
+    void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
 };
 
 // MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
@@ -479,6 +591,15 @@
 
 };  // class NBLog
 
+// TODO put somewhere else
+static inline int64_t get_monotonic_ns() {
+    timespec ts;
+    if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+        return (uint64_t) ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+    }
+    return 0; // should not happen.
+}
+
 }   // namespace android
 
 #endif  // ANDROID_MEDIA_NBLOG_H
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index f6107fd..142ae07 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -7243,6 +7243,16 @@
             ALOGE("Failed to set parameter 'stop-time-us' (err %d)", err);
             return err;
         }
+
+        int64_t stopTimeOffsetUs;
+        err = statusFromBinderStatus(
+                mGraphicBufferSource->getStopTimeOffsetUs(&stopTimeOffsetUs));
+
+        if (err != OK) {
+            ALOGE("Failed to get stop time offset (err %d)", err);
+            return err;
+        }
+        mInputFormat->setInt64("android._stop-time-offset-us", stopTimeOffsetUs);
     }
 
     int32_t dummy;
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 478e306..5fcb1fe 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -1,3 +1,9 @@
+cc_library_headers {
+    name: "libstagefright_headers",
+    export_include_dirs: ["include"],
+    vendor_available: true,
+}
+
 cc_library_shared {
     name: "libstagefright",
 
@@ -91,6 +97,7 @@
         "libnativewindow",
 
         "libmedia_helper",
+        "libstagefright_flacdec",
         "libstagefright_foundation",
         "libdl",
         "libRScpp",
@@ -153,6 +160,7 @@
     "codecs/*",
     "colorconversion",
     "filters",
+    "flac/dec",
     "foundation",
     "http",
     "httplive",
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 4ccd2d0..6a5a229 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -58,6 +58,8 @@
       mOutSampleRate(outSampleRate > 0 ? outSampleRate : sampleRate),
       mTrackMaxAmplitude(false),
       mStartTimeUs(0),
+      mStopSystemTimeUs(-1),
+      mLastFrameTimestampUs(0),
       mMaxAmplitude(0),
       mPrevSampleTimeUs(0),
       mInitialReadTimeUs(0),
@@ -175,6 +177,7 @@
     }
 
     mStarted = false;
+    mStopSystemTimeUs = -1;
     mFrameAvailableCondition.signal();
 
     mRecord->stop();
@@ -286,6 +289,21 @@
     return OK;
 }
 
+status_t AudioSource::setStopTimeUs(int64_t stopTimeUs) {
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("Set stoptime: %lld us", (long long)stopTimeUs);
+
+    if (stopTimeUs < -1) {
+        ALOGE("Invalid stop time %lld us", (long long)stopTimeUs);
+        return BAD_VALUE;
+    } else if (stopTimeUs == -1) {
+        ALOGI("reset stopTime to be -1");
+    }
+
+    mStopSystemTimeUs = stopTimeUs;
+    return OK;
+}
+
 void AudioSource::signalBufferReturned(MediaBuffer *buffer) {
     ALOGV("signalBufferReturned: %p", buffer->data());
     Mutex::Autolock autoLock(mLock);
@@ -338,6 +356,12 @@
         return OK;
     }
 
+    if (mStopSystemTimeUs != -1 && timeUs >= mStopSystemTimeUs) {
+        ALOGV("Drop Audio frame at %lld  stop time: %lld us",
+                (long long)timeUs, (long long)mStopSystemTimeUs);
+        return OK;
+    }
+
     if (mNumFramesReceived == 0 && mPrevSampleTimeUs == 0) {
         mInitialReadTimeUs = timeUs;
         // Initial delay
@@ -346,6 +370,7 @@
         }
         mPrevSampleTimeUs = mStartTimeUs;
     }
+    mLastFrameTimestampUs = timeUs;
 
     size_t numLostBytes = 0;
     if (mNumFramesReceived > 0) {  // Ignore earlier frame lost
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index a569f5d..61a2b5f 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -220,6 +220,7 @@
       mNumFramesEncoded(0),
       mTimeBetweenFrameCaptureUs(0),
       mFirstFrameTimeUs(0),
+      mStopSystemTimeUs(-1),
       mNumFramesDropped(0),
       mNumGlitches(0),
       mGlitchDurationThresholdUs(200000),
@@ -879,6 +880,7 @@
     {
         Mutex::Autolock autoLock(mLock);
         mStarted = false;
+        mStopSystemTimeUs = -1;
         mFrameAvailableCondition.signal();
 
         int64_t token;
@@ -1095,12 +1097,33 @@
     return OK;
 }
 
+status_t CameraSource::setStopTimeUs(int64_t stopTimeUs) {
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("Set stoptime: %lld us", (long long)stopTimeUs);
+
+    if (stopTimeUs < -1) {
+        ALOGE("Invalid stop time %lld us", (long long)stopTimeUs);
+        return BAD_VALUE;
+    } else if (stopTimeUs == -1) {
+        ALOGI("reset stopTime to be -1");
+    }
+
+    mStopSystemTimeUs = stopTimeUs;
+    return OK;
+}
+
 bool CameraSource::shouldSkipFrameLocked(int64_t timestampUs) {
     if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
         ALOGV("Drop frame at %lld/%lld us", (long long)timestampUs, (long long)mStartTimeUs);
         return true;
     }
 
+    if (mStopSystemTimeUs != -1 && timestampUs >= mStopSystemTimeUs) {
+        ALOGV("Drop Camera frame at %lld  stop time: %lld us",
+                (long long)timestampUs, (long long)mStopSystemTimeUs);
+        return true;
+    }
+
     // May need to skip frame or modify timestamp. Currently implemented
     // by the subclass CameraSourceTimeLapse.
     if (skipCurrentFrame(timestampUs)) {
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
old mode 100755
new mode 100644
index b48257f..52e1626
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -343,6 +343,7 @@
 
     void dumpTimeStamps();
 
+    int64_t getStartTimeOffsetScaledTimeUs() const;
     int32_t getStartTimeOffsetScaledTime() const;
 
     static void *ThreadWrapper(void *me);
@@ -2133,13 +2134,17 @@
     if (mDone) {
         return OK;
     }
-    mDone = true;
+
     if (stopSource) {
         ALOGD("%s track source stopping", getTrackType());
         mSource->stop();
         ALOGD("%s track source stopped", getTrackType());
     }
 
+    // Set mDone to be true after sucessfully stop mSource as mSource may be still outputting
+    // buffers to the writer.
+    mDone = true;
+
     void *dummy;
     pthread_join(mThread, &dummy);
     status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
@@ -3158,7 +3163,7 @@
 }
 
 int64_t MPEG4Writer::Track::getDurationUs() const {
-    return mTrackDurationUs;
+    return mTrackDurationUs + getStartTimeOffsetScaledTimeUs();
 }
 
 int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
@@ -3642,14 +3647,18 @@
     mOwner->endBox();  // pasp
 }
 
-int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
+int64_t MPEG4Writer::Track::getStartTimeOffsetScaledTimeUs() const {
     int64_t trackStartTimeOffsetUs = 0;
     int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
     if (mStartTimestampUs != moovStartTimeUs) {
         CHECK_GT(mStartTimestampUs, moovStartTimeUs);
         trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
     }
-    return (trackStartTimeOffsetUs *  mTimeScale + 500000LL) / 1000000LL;
+    return trackStartTimeOffsetUs;
+}
+
+int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
+    return (getStartTimeOffsetScaledTimeUs() *  mTimeScale + 500000LL) / 1000000LL;
 }
 
 void MPEG4Writer::Track::writeSttsBox() {
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index bb20850..cfee943 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -54,7 +54,7 @@
     void stopSource();
     void pause();
     void resume();
-
+    status_t setStopTimeUs(int64_t stopTimeUs);
     bool readBuffer(MediaBuffer **buffer);
 
 protected:
@@ -66,6 +66,7 @@
         kWhatStart = 'msta',
         kWhatStop,
         kWhatPull,
+        kWhatSetStopTimeUs,
     };
 
     sp<MediaSource> mSource;
@@ -161,6 +162,12 @@
     return err;
 }
 
+status_t MediaCodecSource::Puller::setStopTimeUs(int64_t stopTimeUs) {
+    sp<AMessage> msg = new AMessage(kWhatSetStopTimeUs, this);
+    msg->setInt64("stop-time-us", stopTimeUs);
+    return postSynchronouslyAndReturnError(msg);
+}
+
 status_t MediaCodecSource::Puller::start(const sp<MetaData> &meta, const sp<AMessage> &notify) {
     ALOGV("puller (%s) start", mIsAudio ? "audio" : "video");
     mLooper->start(
@@ -250,6 +257,20 @@
             break;
         }
 
+        case kWhatSetStopTimeUs:
+        {
+            sp<AReplyToken> replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+            int64_t stopTimeUs;
+            CHECK(msg->findInt64("stop-time-us", &stopTimeUs));
+            status_t err = mSource->setStopTimeUs(stopTimeUs);
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+            response->postReply(replyID);
+            break;
+        }
+
         case kWhatStop:
         {
             mSource->stop();
@@ -364,11 +385,8 @@
 }
 
 
-status_t MediaCodecSource::setStopStimeUs(int64_t stopTimeUs) {
-    if (!(mFlags & FLAG_USE_SURFACE_INPUT)) {
-        return OK;
-    }
-    sp<AMessage> msg = new AMessage(kWhatSetStopTimeOffset, mReflector);
+status_t MediaCodecSource::setStopTimeUs(int64_t stopTimeUs) {
+    sp<AMessage> msg = new AMessage(kWhatSetStopTimeUs, mReflector);
     msg->setInt64("stop-time-us", stopTimeUs);
     return postSynchronouslyAndReturnError(msg);
 }
@@ -986,12 +1004,21 @@
 
         mStopping = true;
 
+        int64_t timeoutUs = kStopTimeoutUs;
         // if using surface, signal source EOS and wait for EOS to come back.
         // otherwise, stop puller (which also clears the input buffer queue)
         // and wait for the EOS message. We cannot call source->stop() because
         // the encoder may still be processing input buffers.
         if (mFlags & FLAG_USE_SURFACE_INPUT) {
             mEncoder->signalEndOfInputStream();
+            // Increase the timeout if there is delay in the GraphicBufferSource
+            sp<AMessage> inputFormat;
+            int64_t stopTimeOffsetUs;
+            if (mEncoder->getInputFormat(&inputFormat) == OK &&
+                    inputFormat->findInt64("android._stop-time-offset-us", &stopTimeOffsetUs) &&
+                    stopTimeOffsetUs > 0) {
+                timeoutUs += stopTimeOffsetUs;
+            }
         } else {
             mPuller->stop();
         }
@@ -999,7 +1026,7 @@
         // complete stop even if encoder/puller stalled
         sp<AMessage> timeoutMsg = new AMessage(kWhatStopStalled, mReflector);
         timeoutMsg->setInt32("generation", mGeneration);
-        timeoutMsg->post(kStopTimeoutUs);
+        timeoutMsg->post(timeoutUs);
         break;
     }
 
@@ -1055,7 +1082,7 @@
         response->postReply(replyID);
         break;
     }
-    case kWhatSetStopTimeOffset:
+    case kWhatSetStopTimeUs:
     {
         sp<AReplyToken> replyID;
         CHECK(msg->senderAwaitsResponse(&replyID));
@@ -1063,11 +1090,13 @@
         int64_t stopTimeUs;
         CHECK(msg->findInt64("stop-time-us", &stopTimeUs));
 
-        // Propagate the timestamp offset to GraphicBufferSource.
+        // Propagate the stop time to GraphicBufferSource.
         if (mFlags & FLAG_USE_SURFACE_INPUT) {
             sp<AMessage> params = new AMessage;
             params->setInt64("stop-time-us", stopTimeUs);
             err = mEncoder->setParameters(params);
+        } else {
+            err = mPuller->setStopTimeUs(stopTimeUs);
         }
 
         sp<AMessage> response = new AMessage;
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index 0cf6fbf..9278381 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -32,6 +32,8 @@
 
 #include <ui/GraphicBuffer.h>
 
+#include <system/window.h>
+
 // Maximum late time allowed for a video frame to be rendered. When a video
 // frame arrives later than this number, it will be discarded without rendering.
 static const int64_t kMaxAllowedVideoLateTimeUs = 40000ll;
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index ea7d5af..90b8603 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -36,6 +36,12 @@
 
 //static
 sp<SimpleDecodingSource> SimpleDecodingSource::Create(
+        const sp<IMediaSource> &source, uint32_t flags) {
+    return SimpleDecodingSource::Create(source, flags, nullptr, nullptr);
+}
+
+//static
+sp<SimpleDecodingSource> SimpleDecodingSource::Create(
         const sp<IMediaSource> &source, uint32_t flags, const sp<ANativeWindow> &nativeWindow,
         const char *desiredCodec) {
     sp<Surface> surface = static_cast<Surface*>(nativeWindow.get());
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 621c2ce..0aea8e1 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1069,6 +1069,16 @@
         buffer->meta()->setInt32("csd", true);
         buffer->meta()->setInt64("timeUs", 0);
         msg->setBuffer("csd-2", buffer);
+    } else if (meta->findData(kKeyFlacMetadata, &type, &data, &size)) {
+        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
+        if (buffer.get() == NULL || buffer->base() == NULL) {
+            return NO_MEMORY;
+        }
+        memcpy(buffer->data(), data, size);
+
+        buffer->meta()->setInt32("csd", true);
+        buffer->meta()->setInt64("timeUs", 0);
+        msg->setBuffer("csd-0", buffer);
     } else if (meta->findData(kKeyVp9CodecPrivate, &type, &data, &size)) {
         sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
         if (buffer.get() == NULL || buffer->base() == NULL) {
@@ -1552,6 +1562,7 @@
     { MEDIA_MIMETYPE_AUDIO_VORBIS,      AUDIO_FORMAT_VORBIS },
     { MEDIA_MIMETYPE_AUDIO_OPUS,        AUDIO_FORMAT_OPUS},
     { MEDIA_MIMETYPE_AUDIO_AC3,         AUDIO_FORMAT_AC3},
+    { MEDIA_MIMETYPE_AUDIO_FLAC,        AUDIO_FORMAT_FLAC},
     { 0, AUDIO_FORMAT_INVALID }
 };
 
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index 7193435..a745692 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -80,7 +80,16 @@
     for (size_t j = 0; j < sizeOfScalingList; ++j) {
         if (nextScale != 0) {
             signed delta_scale = parseSE(br);
-            nextScale = (lastScale + delta_scale + 256) % 256;
+            // ISO_IEC_14496-10_201402-ITU, 7.4.2.1.1.1, The value of delta_scale
+            // shall be in the range of −128 to +127, inclusive.
+            if (delta_scale < -128) {
+                ALOGW("delta_scale (%d) is below range, capped to -128", delta_scale);
+                delta_scale = -128;
+            } else if (delta_scale > 127) {
+                ALOGW("delta_scale (%d) is above range, capped to 127", delta_scale);
+                delta_scale = 127;
+            }
+            nextScale = (lastScale + (delta_scale + 256)) % 256;
         }
 
         lastScale = (nextScale == 0) ? lastScale : nextScale;
diff --git a/media/libstagefright/codecs/flac/dec/Android.bp b/media/libstagefright/codecs/flac/dec/Android.bp
new file mode 100644
index 0000000..6ac264d
--- /dev/null
+++ b/media/libstagefright/codecs/flac/dec/Android.bp
@@ -0,0 +1,36 @@
+cc_library_shared {
+    name: "libstagefright_soft_flacdec",
+
+    srcs: [
+        "SoftFlacDecoder.cpp",
+    ],
+
+    include_dirs: [
+        "external/flac/include",
+        "frameworks/av/media/libstagefright/flac/dec",
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/native/include/media/openmax",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+        "libstagefright_flacdec",
+        "libstagefright_omx",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+}
diff --git a/media/libstagefright/codecs/flac/dec/MODULE_LICENSE_APACHE2 b/media/libstagefright/codecs/flac/dec/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libstagefright/codecs/flac/dec/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/codecs/flac/dec/NOTICE b/media/libstagefright/codecs/flac/dec/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/media/libstagefright/codecs/flac/dec/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
new file mode 100644
index 0000000..f89688c
--- /dev/null
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2017 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_NDEBUG 0
+#define LOG_TAG "SoftFlacDecoder"
+#include <utils/Log.h>
+
+#include "SoftFlacDecoder.h"
+#include <OMX_AudioExt.h>
+#include <OMX_IndexExt.h>
+
+#include <cutils/properties.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/misc.h>
+
+namespace android {
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+
+SoftFlacDecoder::SoftFlacDecoder(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : SimpleSoftOMXComponent(name, callbacks, appData, component),
+      mFLACDecoder(NULL),
+      mHasStreamInfo(false),
+      mInputBufferCount(0),
+      mSignalledError(false),
+      mOutputPortSettingsChange(NONE) {
+    ALOGV("ctor:");
+    memset(&mStreamInfo, 0, sizeof(mStreamInfo));
+    initPorts();
+    initDecoder();
+}
+
+SoftFlacDecoder::~SoftFlacDecoder() {
+    ALOGV("dtor:");
+}
+
+void SoftFlacDecoder::initPorts() {
+    ALOGV("initPorts:");
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+
+    def.nPortIndex = 0;
+    def.eDir = OMX_DirInput;
+    def.nBufferCountMin = kNumInputBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = 8192;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 1;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/flac");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingFLAC;
+
+    addPort(def);
+
+    def.nPortIndex = 1;
+    def.eDir = OMX_DirOutput;
+    def.nBufferCountMin = kNumOutputBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = 4096 * FLACDecoder::kMaxChannels;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 2;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+    addPort(def);
+}
+
+void SoftFlacDecoder::initDecoder() {
+    ALOGV("initDecoder:");
+    mFLACDecoder = FLACDecoder::Create();
+    if (mFLACDecoder == NULL) {
+        ALOGE("initDecoder: failed to create FLACDecoder");
+        mSignalledError = true;
+    }
+}
+
+OMX_ERRORTYPE SoftFlacDecoder::initCheck() const {
+    if (mSignalledError) {
+        if (mFLACDecoder == NULL) {
+            ALOGE("initCheck: failed due to NULL encoder");
+            return OMX_ErrorDynamicResourcesUnavailable;
+        }
+        return OMX_ErrorUndefined;
+    }
+
+    return SimpleSoftOMXComponent::initCheck();
+}
+
+OMX_ERRORTYPE SoftFlacDecoder::internalGetParameter(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    ALOGV("internalGetParameter: index(%x)", index);
+    switch ((OMX_U32)index) {
+        case OMX_IndexParamAudioFlac:
+        {
+            OMX_AUDIO_PARAM_FLACTYPE *flacParams =
+                (OMX_AUDIO_PARAM_FLACTYPE *)params;
+
+            if (!isValidOMXParam(flacParams)) {
+                ALOGE("internalGetParameter(OMX_IndexParamAudioFlac): invalid omx params");
+                return OMX_ErrorBadParameter;
+            }
+
+            if (flacParams->nPortIndex != 0) {
+                ALOGE("internalGetParameter(OMX_IndexParamAudioFlac): bad port index");
+                return OMX_ErrorBadPortIndex;
+            }
+
+            flacParams->nCompressionLevel = 0;
+
+            if (isConfigured()) {
+                flacParams->nChannels = mStreamInfo.channels;
+                flacParams->nSampleRate = mStreamInfo.sample_rate;
+            } else {
+                flacParams->nChannels = 1;
+                flacParams->nSampleRate = 44100;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (!isValidOMXParam(pcmParams)) {
+                ALOGE("internalGetParameter(OMX_IndexParamAudioPcm): invalid omx params");
+                return OMX_ErrorBadParameter;
+            }
+
+            if (pcmParams->nPortIndex != 1) {
+                ALOGE("internalGetParameter(OMX_IndexParamAudioPcm): bad port index");
+                return OMX_ErrorBadPortIndex;
+            }
+
+            pcmParams->eNumData = OMX_NumericalDataSigned;
+            pcmParams->eEndian = OMX_EndianBig;
+            pcmParams->bInterleaved = OMX_TRUE;
+            pcmParams->nBitPerSample = 16;
+            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+            pcmParams->eChannelMapping[2] = OMX_AUDIO_ChannelCF;
+            pcmParams->eChannelMapping[3] = OMX_AUDIO_ChannelLFE;
+            pcmParams->eChannelMapping[4] = OMX_AUDIO_ChannelLS;
+            pcmParams->eChannelMapping[5] = OMX_AUDIO_ChannelRS;
+
+            if (isConfigured()) {
+                pcmParams->nChannels = mStreamInfo.channels;
+                pcmParams->nSamplingRate = mStreamInfo.sample_rate;
+            } else {
+                pcmParams->nChannels = 1;
+                pcmParams->nSamplingRate = 44100;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalGetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE SoftFlacDecoder::internalSetParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    ALOGV("internalSetParameter: index(%x)", (int)index);
+    switch ((int)index) {
+        case OMX_IndexParamStandardComponentRole:
+        {
+            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+                (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+            if (!isValidOMXParam(roleParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (strncmp((const char *)roleParams->cRole,
+                        "audio_decoder.flac",
+                        OMX_MAX_STRINGNAME_SIZE - 1) != 0) {
+                return OMX_ErrorInvalidComponentName;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (!isValidOMXParam(pcmParams)) {
+                return OMX_ErrorBadParameter;
+            }
+
+            if (pcmParams->nPortIndex != 1) {
+                return OMX_ErrorBadPortIndex;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalSetParameter(index, params);
+    }
+}
+
+bool SoftFlacDecoder::isConfigured() const {
+    return mHasStreamInfo;
+}
+
+void SoftFlacDecoder::onQueueFilled(OMX_U32 /* portIndex */) {
+    ALOGV("onQueueFilled:");
+    if (mSignalledError || mOutputPortSettingsChange != NONE) {
+        return;
+    }
+
+    List<BufferInfo *> &inQueue = getPortQueue(0);
+    List<BufferInfo *> &outQueue = getPortQueue(1);
+
+    while (!inQueue.empty() && !outQueue.empty()) {
+        BufferInfo *inInfo = *inQueue.begin();
+        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+        uint8_t* inBuffer = inHeader->pBuffer + inHeader->nOffset;
+        uint32_t inBufferLength = inHeader->nFilledLen;
+        bool endOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0;
+
+        if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
+            ALOGE("onQueueFilled: first buffer should have OMX_BUFFERFLAG_CODECCONFIG set");
+            inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
+        }
+        if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) {
+            status_t decoderErr = mFLACDecoder->parseMetadata(inBuffer, inBufferLength);
+            mInputBufferCount++;
+
+            if (decoderErr != OK && decoderErr != WOULD_BLOCK) {
+                ALOGE("onQueueFilled: FLACDecoder parseMetaData returns error %d", decoderErr);
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorStreamCorrupt, decoderErr, NULL);
+                return;
+            }
+
+            inInfo->mOwnedByUs = false;
+            inQueue.erase(inQueue.begin());
+            notifyEmptyBufferDone(inHeader);
+
+            if (decoderErr == WOULD_BLOCK) {
+                continue;
+            }
+            mStreamInfo = mFLACDecoder->getStreamInfo();
+            mHasStreamInfo = true;
+
+            // Only send out port settings changed event if both sample rate
+            // and numChannels are valid.
+            if (mStreamInfo.sample_rate && mStreamInfo.channels) {
+                ALOGD("onQueueFilled: initially configuring decoder: %d Hz, %d channels",
+                    mStreamInfo.sample_rate, mStreamInfo.channels);
+
+                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+                mOutputPortSettingsChange = AWAITING_DISABLED;
+            }
+            return;
+        }
+
+        BufferInfo *outInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+        short *outBuffer =
+                reinterpret_cast<short *>(outHeader->pBuffer + outHeader->nOffset);
+        size_t outBufferSize = outHeader->nAllocLen - outHeader->nOffset;
+
+        status_t decoderErr = mFLACDecoder->decodeOneFrame(
+                inBuffer, inBufferLength, outBuffer, &outBufferSize);
+        if (decoderErr != OK) {
+            ALOGE("onQueueFilled: FLACDecoder decodeOneFrame returns error %d", decoderErr);
+            mSignalledError = true;
+            notify(OMX_EventError, OMX_ErrorStreamCorrupt, decoderErr, NULL);
+            return;
+        }
+
+        mInputBufferCount++;
+        int64_t ts = inHeader->nTimeStamp;
+        inInfo->mOwnedByUs = false;
+        inQueue.erase(inQueue.begin());
+        notifyEmptyBufferDone(inHeader);
+
+        if (endOfInput) {
+            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+        } else if (outBufferSize == 0) {
+            continue;
+        } else {
+            outHeader->nFlags = 0;
+        }
+
+        outHeader->nFilledLen = outBufferSize;
+        outHeader->nTimeStamp = ts;
+
+        outInfo->mOwnedByUs = false;
+        outQueue.erase(outQueue.begin());
+        notifyFillBufferDone(outHeader);
+    }
+}
+
+void SoftFlacDecoder::onPortFlushCompleted(OMX_U32 portIndex) {
+    ALOGV("onPortFlushCompleted: portIndex(%u)", portIndex);
+    if (portIndex == 0) {
+        drainDecoder();
+    }
+}
+
+void SoftFlacDecoder::drainDecoder() {
+    mFLACDecoder->flush();
+}
+
+void SoftFlacDecoder::onReset() {
+    drainDecoder();
+
+    memset(&mStreamInfo, 0, sizeof(mStreamInfo));
+    mHasStreamInfo = false;
+    mInputBufferCount = 0;
+    mSignalledError = false;
+    mOutputPortSettingsChange = NONE;
+}
+
+void SoftFlacDecoder::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
+    ALOGV("onPortEnableCompleted: portIndex(%u), enabled(%d)", portIndex, enabled);
+    if (portIndex != 1) {
+        return;
+    }
+
+    switch (mOutputPortSettingsChange) {
+        case NONE:
+            break;
+
+        case AWAITING_DISABLED:
+        {
+            CHECK(!enabled);
+            mOutputPortSettingsChange = AWAITING_ENABLED;
+            PortInfo *info = editPortInfo(1 /* portIndex */);
+            if (!info->mDef.bEnabled) {
+                info->mDef.nBufferSize = mStreamInfo.max_blocksize * mStreamInfo.channels * 2;
+            }
+            break;
+        }
+
+        default:
+        {
+            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
+            CHECK(enabled);
+            mOutputPortSettingsChange = NONE;
+            break;
+        }
+    }
+}
+
+}  // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+    ALOGV("createSoftOMXComponent: flac decoder");
+    return new android::SoftFlacDecoder(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
new file mode 100644
index 0000000..c09081d
--- /dev/null
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 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 SOFT_FLAC_DECODER_H
+#define SOFT_FLAC_DECODER_H
+
+#include "FLACDecoder.h"
+#include "SimpleSoftOMXComponent.h"
+
+namespace android {
+
+struct SoftFlacDecoder : public SimpleSoftOMXComponent {
+    SoftFlacDecoder(const char *name,
+            const OMX_CALLBACKTYPE *callbacks,
+            OMX_PTR appData,
+            OMX_COMPONENTTYPE **component);
+
+    virtual OMX_ERRORTYPE initCheck() const override;
+
+protected:
+    virtual ~SoftFlacDecoder();
+
+    virtual OMX_ERRORTYPE internalGetParameter(
+            OMX_INDEXTYPE index, OMX_PTR params) override;
+
+    virtual OMX_ERRORTYPE internalSetParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params) override;
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+    virtual void onPortFlushCompleted(OMX_U32 portIndex) override;
+    virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled) override;
+    virtual void onReset() override;
+
+private:
+    enum {
+        kNumInputBuffers   = 4,
+        kNumOutputBuffers  = 4,
+    };
+
+    sp<FLACDecoder> mFLACDecoder;
+    FLAC__StreamMetadata_StreamInfo mStreamInfo;
+    bool mHasStreamInfo;
+    size_t mInputBufferCount;
+    bool mSignalledError;
+
+    enum {
+        NONE,
+        AWAITING_DISABLED,
+        AWAITING_ENABLED
+    } mOutputPortSettingsChange;
+
+    void initPorts();
+    void initDecoder();
+    bool isConfigured() const;
+    void drainDecoder();
+
+    DISALLOW_EVIL_CONSTRUCTORS(SoftFlacDecoder);
+};
+
+}  // namespace android
+
+#endif  // SOFT_FLAC_DECODER_H
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index be04e08..14dd250 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -23,6 +23,9 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 
+static int kDefaultChannelCount = 1;
+static int kDefaultSamplingRate = 48000;
+
 extern "C" {
     #include <Tremolo/codec_internal.h>
 
@@ -148,8 +151,8 @@
             vorbisParams->bDownmix = OMX_FALSE;
 
             if (!isConfigured()) {
-                vorbisParams->nChannels = 1;
-                vorbisParams->nSampleRate = 44100;
+                vorbisParams->nChannels = kDefaultChannelCount;
+                vorbisParams->nSampleRate = kDefaultSamplingRate;
             } else {
                 vorbisParams->nChannels = mVi->channels;
                 vorbisParams->nSampleRate = mVi->rate;
@@ -157,7 +160,6 @@
                 vorbisParams->nMinBitRate = mVi->bitrate_lower;
                 vorbisParams->nMaxBitRate = mVi->bitrate_upper;
             }
-
             return OMX_ErrorNone;
         }
 
@@ -183,8 +185,8 @@
             pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
 
             if (!isConfigured()) {
-                pcmParams->nChannels = 1;
-                pcmParams->nSamplingRate = 44100;
+                pcmParams->nChannels = kDefaultChannelCount;
+                pcmParams->nSamplingRate = kDefaultSamplingRate;
             } else {
                 pcmParams->nChannels = mVi->channels;
                 pcmParams->nSamplingRate = mVi->rate;
@@ -313,8 +315,12 @@
             mState = new vorbis_dsp_state;
             CHECK_EQ(0, vorbis_dsp_init(mState, mVi));
 
-            notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
-            mOutputPortSettingsChange = AWAITING_DISABLED;
+            if (mVi->rate != kDefaultSamplingRate ||
+                    mVi->channels != kDefaultChannelCount) {
+                ALOGV("vorbis: rate/channels changed: %ld/%d", mVi->rate, mVi->channels);
+                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+                mOutputPortSettingsChange = AWAITING_DISABLED;
+            }
         }
 
         inQueue.erase(inQueue.begin());
diff --git a/media/libstagefright/colorconversion/Android.bp b/media/libstagefright/colorconversion/Android.bp
index 11fe5eb..16e9ded 100644
--- a/media/libstagefright/colorconversion/Android.bp
+++ b/media/libstagefright/colorconversion/Android.bp
@@ -10,7 +10,10 @@
         "frameworks/native/include/media/openmax",
     ],
 
-    shared_libs: ["libui"],
+    shared_libs: [
+        "libui",
+        "libnativewindow",
+    ],
 
     static_libs: ["libyuv_static"],
 
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 536d40d..a07787a 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -30,10 +30,6 @@
 
 namespace android {
 
-static bool runningInEmulator() {
-    char prop[PROPERTY_VALUE_MAX];
-    return (property_get("ro.kernel.qemu", prop, NULL) > 0);
-}
 
 static int ALIGN(int x, int y) {
     // y must be a power of 2.
@@ -108,7 +104,7 @@
     size_t bufHeight = mCropHeight;
 
     // hardware has YUV12 and RGBA8888 support, so convert known formats
-    if (!runningInEmulator()) {
+    {
         switch (mColorFormat) {
             case OMX_COLOR_FormatYUV420Planar:
             case OMX_COLOR_FormatYUV420SemiPlanar:
@@ -205,7 +201,7 @@
 }
 
 std::list<FrameRenderTracker::Info> SoftwareRenderer::render(
-        const void *data, size_t size, int64_t mediaTimeUs, nsecs_t renderTimeNs,
+        const void *data, size_t , int64_t mediaTimeUs, nsecs_t renderTimeNs,
         void* /*platformPrivate*/, const sp<AMessage>& format) {
     resetFormatIfChanged(format);
     FrameRenderTracker::Info *info = NULL;
@@ -244,14 +240,15 @@
                 buf->stride, buf->height,
                 0, 0, mCropWidth - 1, mCropHeight - 1);
     } else if (mColorFormat == OMX_COLOR_FormatYUV420Planar) {
-        if ((size_t)mWidth * mHeight * 3 / 2 > size) {
-            goto skip_copying;
-        }
         const uint8_t *src_y = (const uint8_t *)data;
         const uint8_t *src_u =
                 (const uint8_t *)data + mWidth * mHeight;
         const uint8_t *src_v = src_u + (mWidth / 2 * mHeight / 2);
 
+        src_y +=mCropLeft + mCropTop * mWidth;
+        src_u +=(mCropLeft + mCropTop * mWidth / 2)/2;
+        src_v +=(mCropLeft + mCropTop * mWidth / 2)/2;
+
         uint8_t *dst_y = (uint8_t *)dst;
         size_t dst_y_size = buf->stride * buf->height;
         size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
@@ -259,6 +256,10 @@
         uint8_t *dst_v = dst_y + dst_y_size;
         uint8_t *dst_u = dst_v + dst_c_size;
 
+        dst_y += mCropTop * buf->stride + mCropLeft;
+        dst_v += (mCropTop/2) * dst_c_stride + mCropLeft/2;
+        dst_u += (mCropTop/2) * dst_c_stride + mCropLeft/2;
+
         for (int y = 0; y < mCropHeight; ++y) {
             memcpy(dst_y, src_y, mCropWidth);
 
@@ -277,12 +278,12 @@
         }
     } else if (mColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
             || mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
-        if ((size_t)mWidth * mHeight * 3 / 2 > size) {
-            goto skip_copying;
-        }
         const uint8_t *src_y = (const uint8_t *)data;
         const uint8_t *src_uv = (const uint8_t *)data
-                + mWidth * (mHeight - mCropTop / 2);
+                + mWidth * mHeight;
+
+        src_y += mCropLeft + mCropTop * mWidth;
+        src_uv += (mCropLeft + mCropTop * mWidth) / 2;
 
         uint8_t *dst_y = (uint8_t *)dst;
 
@@ -292,6 +293,10 @@
         uint8_t *dst_v = dst_y + dst_y_size;
         uint8_t *dst_u = dst_v + dst_c_size;
 
+        dst_y += mCropTop * buf->stride + mCropLeft;
+        dst_v += (mCropTop/2) * dst_c_stride + mCropLeft/2;
+        dst_u += (mCropTop/2) * dst_c_stride + mCropLeft/2;
+
         for (int y = 0; y < mCropHeight; ++y) {
             memcpy(dst_y, src_y, mCropWidth);
 
@@ -311,11 +316,8 @@
             dst_v += dst_c_stride;
         }
     } else if (mColorFormat == OMX_COLOR_Format24bitRGB888) {
-        if ((size_t)mWidth * mHeight * 3 > size) {
-            goto skip_copying;
-        }
-        uint8_t* srcPtr = (uint8_t*)data;
-        uint8_t* dstPtr = (uint8_t*)dst;
+        uint8_t* srcPtr = (uint8_t*)data + mWidth * mCropTop * 3 + mCropLeft * 3;
+        uint8_t* dstPtr = (uint8_t*)dst + buf->stride * mCropTop * 3 + mCropLeft * 3;
 
         for (size_t y = 0; y < (size_t)mCropHeight; ++y) {
             memcpy(dstPtr, srcPtr, mCropWidth * 3);
@@ -323,14 +325,11 @@
             dstPtr += buf->stride * 3;
         }
     } else if (mColorFormat == OMX_COLOR_Format32bitARGB8888) {
-        if ((size_t)mWidth * mHeight * 4 > size) {
-            goto skip_copying;
-        }
         uint8_t *srcPtr, *dstPtr;
 
         for (size_t y = 0; y < (size_t)mCropHeight; ++y) {
-            srcPtr = (uint8_t*)data + mWidth * 4 * y;
-            dstPtr = (uint8_t*)dst + buf->stride * 4 * y;
+            srcPtr = (uint8_t*)data + mWidth * 4 * (y + mCropTop) + mCropLeft * 4;
+            dstPtr = (uint8_t*)dst + buf->stride * 4 * (y + mCropTop) + mCropLeft * 4;
             for (size_t x = 0; x < (size_t)mCropWidth; ++x) {
                 uint8_t a = *srcPtr++;
                 for (size_t i = 0; i < 3; ++i) {   // copy RGB
@@ -340,11 +339,8 @@
             }
         }
     } else if (mColorFormat == OMX_COLOR_Format32BitRGBA8888) {
-        if ((size_t)mWidth * mHeight * 4 > size) {
-            goto skip_copying;
-        }
-        uint8_t* srcPtr = (uint8_t*)data;
-        uint8_t* dstPtr = (uint8_t*)dst;
+        uint8_t* srcPtr = (uint8_t*)data + mWidth * mCropTop * 4 + mCropLeft * 4;
+        uint8_t* dstPtr = (uint8_t*)dst + buf->stride * mCropTop * 4 + mCropLeft * 4;
 
         for (size_t y = 0; y < (size_t)mCropHeight; ++y) {
             memcpy(dstPtr, srcPtr, mCropWidth * 4);
diff --git a/media/libstagefright/data/media_codecs_google_audio.xml b/media/libstagefright/data/media_codecs_google_audio.xml
index b957b0c..632088a 100644
--- a/media/libstagefright/data/media_codecs_google_audio.xml
+++ b/media/libstagefright/data/media_codecs_google_audio.xml
@@ -61,6 +61,11 @@
             <Limit name="sample-rate" ranges="8000-96000" />
             <Limit name="bitrate" range="1-10000000" />
         </MediaCodec>
+        <MediaCodec name="OMX.google.flac.decoder" type="audio/flac">
+            <Limit name="channel-count" max="8" />
+            <Limit name="sample-rate" ranges="1-655350" />
+            <Limit name="bitrate" range="1-21000000" />
+        </MediaCodec>
     </Decoders>
     <Encoders>
         <MediaCodec name="OMX.google.aac.encoder" type="audio/mp4a-latm">
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
new file mode 100644
index 0000000..284c25f
--- /dev/null
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -0,0 +1,34 @@
+cc_library_shared {
+    name: "libstagefright_flacdec",
+
+    srcs: [
+        "FLACDecoder.cpp",
+    ],
+
+    include_dirs: [
+        "external/flac/include",
+        "frameworks/av/media/libstagefright/include",
+    ],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    static_libs: ["libFLAC"],
+
+    shared_libs: [
+        "libcutils",
+        "liblog",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+}
diff --git a/media/libstagefright/flac/dec/FLACDecoder.cpp b/media/libstagefright/flac/dec/FLACDecoder.cpp
new file mode 100644
index 0000000..8c7137c
--- /dev/null
+++ b/media/libstagefright/flac/dec/FLACDecoder.cpp
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2017 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_NDEBUG 0
+#define LOG_TAG "FLACDecoder"
+#include <utils/Log.h>
+
+#include "FLACDecoder.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+// These are the corresponding callbacks with C++ calling conventions
+FLAC__StreamDecoderReadStatus FLACDecoder::readCallback(
+        FLAC__byte buffer[], size_t *bytes) {
+    if (mBuffer == nullptr || mBufferLen == 0) {
+        *bytes = 0;
+        return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+    }
+
+    size_t actual = *bytes;
+    if (actual > mBufferDataSize - mBufferPos) {
+        actual = mBufferDataSize - mBufferPos;
+    }
+    memcpy(buffer, mBuffer + mBufferPos, actual);
+    mBufferPos += actual;
+    *bytes = actual;
+    return (actual == 0 ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
+                        : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE);
+}
+
+FLAC__StreamDecoderWriteStatus FLACDecoder::writeCallback(
+        const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+    if (!mWriteRequested) {
+        ALOGE("writeCallback: unexpected");
+        return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+    }
+
+    mWriteRequested = false;
+    // FLAC decoder doesn't free or realloc buffer until next frame or finish
+    mWriteHeader = frame->header;
+    memmove(mWriteBuffer, buffer, sizeof(const FLAC__int32 * const) * getChannels());
+    mWriteCompleted = true;
+    return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void FLACDecoder::metadataCallback(const FLAC__StreamMetadata *metadata)
+{
+    switch (metadata->type) {
+        case FLAC__METADATA_TYPE_STREAMINFO:
+        {
+            if (mStreamInfoValid) {
+                ALOGE("metadataCallback: unexpected STREAMINFO");
+            } else {
+                mStreamInfo = metadata->data.stream_info;
+                mStreamInfoValid = true;
+            }
+            break;
+        }
+
+        /* TODO: enable metadata parsing below.
+        case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+        {
+            const FLAC__StreamMetadata_VorbisComment *vc;
+            vc = &metadata->data.vorbis_comment;
+            for (FLAC__uint32 i = 0; i < vc->num_comments; ++i) {
+                FLAC__StreamMetadata_VorbisComment_Entry *vce;
+                vce = &vc->comments[i];
+                if (mFileMetadata != 0 && vce->entry != NULL) {
+                    parseVorbisComment(mFileMetadata, (const char *) vce->entry,
+                            vce->length);
+                }
+            }
+            break;
+        }
+
+        case FLAC__METADATA_TYPE_PICTURE:
+        {
+            if (mFileMetadata != 0) {
+                const FLAC__StreamMetadata_Picture *p = &metadata->data.picture;
+                mFileMetadata->setData(kKeyAlbumArt,
+                        MetaData::TYPE_NONE, p->data, p->data_length);
+                mFileMetadata->setCString(kKeyAlbumArtMIME, p->mime_type);
+            }
+            break;
+        }
+        */
+
+        default:
+            ALOGW("metadataCallback: unexpected type %u", metadata->type);
+            break;
+    }
+}
+
+void FLACDecoder::errorCallback(FLAC__StreamDecoderErrorStatus status)
+{
+    ALOGE("errorCallback: status=%d", status);
+    mErrorStatus = status;
+}
+
+// Copy samples from FLAC native 32-bit non-interleaved to 16-bit interleaved.
+// These are candidates for optimization if needed.
+static void copyMono8(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned /* nChannels */) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i] << 8;
+    }
+}
+
+static void copyStereo8(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned /* nChannels */) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i] << 8;
+        *dst++ = src[1][i] << 8;
+    }
+}
+
+static void copyMultiCh8(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned nChannels) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        for (unsigned c = 0; c < nChannels; ++c) {
+            *dst++ = src[c][i] << 8;
+        }
+    }
+}
+
+static void copyMono16(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned /* nChannels */) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i];
+    }
+}
+
+static void copyStereo16(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned /* nChannels */) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i];
+        *dst++ = src[1][i];
+    }
+}
+
+static void copyMultiCh16(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned nChannels) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        for (unsigned c = 0; c < nChannels; ++c) {
+            *dst++ = src[c][i];
+        }
+    }
+}
+
+// TODO: 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
+static void copyMono24(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned /* nChannels */) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i] >> 8;
+    }
+}
+
+static void copyStereo24(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned /* nChannels */) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        *dst++ = src[0][i] >> 8;
+        *dst++ = src[1][i] >> 8;
+    }
+}
+
+static void copyMultiCh24(
+        short *dst,
+        const int * src[FLACDecoder::kMaxChannels],
+        unsigned nSamples,
+        unsigned nChannels) {
+    for (unsigned i = 0; i < nSamples; ++i) {
+        for (unsigned c = 0; c < nChannels; ++c) {
+            *dst++ = src[c][i] >> 8;
+        }
+    }
+}
+
+// static
+sp<FLACDecoder> FLACDecoder::Create() {
+    sp<FLACDecoder> decoder = new FLACDecoder();
+    if (decoder->init() != OK) {
+        return NULL;
+    }
+    return decoder;
+}
+
+FLACDecoder::FLACDecoder()
+    : mDecoder(NULL),
+      mBuffer(NULL),
+      mBufferLen(0),
+      mBufferPos(0),
+      mBufferDataSize(0),
+      mStreamInfoValid(false),
+      mWriteRequested(false),
+      mWriteCompleted(false),
+      mErrorStatus((FLAC__StreamDecoderErrorStatus) -1),
+      mCopy(nullptr) {
+    ALOGV("ctor:");
+    memset(&mStreamInfo, 0, sizeof(mStreamInfo));
+    memset(&mWriteHeader, 0, sizeof(mWriteHeader));
+    memset(&mWriteBuffer, 0, sizeof(mWriteBuffer));
+}
+
+FLACDecoder::~FLACDecoder() {
+    ALOGV("dtor:");
+    if (mDecoder != NULL) {
+        FLAC__stream_decoder_delete(mDecoder);
+        mDecoder = NULL;
+    }
+    if (mBuffer != NULL) {
+        free(mBuffer);
+    }
+}
+
+status_t FLACDecoder::init() {
+    ALOGV("init:");
+    // setup libFLAC stream decoder
+    mDecoder = FLAC__stream_decoder_new();
+    if (mDecoder == NULL) {
+        ALOGE("init: failed to create libFLAC stream decoder");
+        return NO_INIT;
+    }
+    FLAC__stream_decoder_set_md5_checking(mDecoder, false);
+    FLAC__stream_decoder_set_metadata_ignore_all(mDecoder);
+    FLAC__stream_decoder_set_metadata_respond(
+            mDecoder, FLAC__METADATA_TYPE_STREAMINFO);
+    /*
+    FLAC__stream_decoder_set_metadata_respond(
+            mDecoder, FLAC__METADATA_TYPE_PICTURE);
+    FLAC__stream_decoder_set_metadata_respond(
+            mDecoder, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+    */
+    static auto read_callback =
+        [] (const FLAC__StreamDecoder * /* decoder */,
+            FLAC__byte buffer[],
+            size_t *bytes,
+            void *client_data) -> FLAC__StreamDecoderReadStatus {
+            return ((FLACDecoder *) client_data)->readCallback(buffer, bytes); };
+
+    static auto write_callback =
+        [] (const FLAC__StreamDecoder * /* decoder */,
+            const FLAC__Frame *frame,
+            const FLAC__int32 * const buffer[],
+            void *client_data) -> FLAC__StreamDecoderWriteStatus {
+            return ((FLACDecoder *) client_data)->writeCallback(frame, buffer); };
+
+    static auto metadata_callback =
+        [] (const FLAC__StreamDecoder * /* decoder */,
+            const FLAC__StreamMetadata *metadata,
+            void *client_data) {
+            ((FLACDecoder *) client_data)->metadataCallback(metadata); };
+
+    static auto error_callback =
+        [] (const FLAC__StreamDecoder * /* decoder */,
+            FLAC__StreamDecoderErrorStatus status,
+            void *client_data) {
+            ((FLACDecoder *) client_data)->errorCallback(status); };
+
+    FLAC__StreamDecoderInitStatus initStatus =
+        FLAC__stream_decoder_init_stream(
+                mDecoder,
+                read_callback,
+                NULL /* seek_callback */,
+                NULL /* tell_callback */,
+                NULL /* length_callback */,
+                NULL /* eof_callback */,
+                write_callback,
+                metadata_callback,
+                error_callback,
+                (void *)this);
+    if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+        ALOGE("init: init_stream failed, returned %d", initStatus);
+        return NO_INIT;
+    }
+    return OK;
+}
+
+void FLACDecoder::flush() {
+    ALOGV("flush:");
+    mBufferPos = 0;
+    mBufferDataSize = 0;
+    mStreamInfoValid = false;
+    if (!FLAC__stream_decoder_reset(mDecoder)) {
+        ALOGE("flush: failed to reset FLAC stream decoder");
+    }
+}
+
+status_t FLACDecoder::parseMetadata(const uint8_t *inBuffer, size_t inBufferLen) {
+    ALOGV("parseMetadata: input size(%zu)", inBufferLen);
+    //hexdump(inBuffer, inBufferLen);
+
+    if (mStreamInfoValid) {
+        ALOGE("parseMetadata: already have full metadata blocks");
+        return ERROR_MALFORMED;
+    }
+
+    status_t err = addDataToBuffer(inBuffer, inBufferLen);
+    if (err != OK) {
+        ALOGE("parseMetadata: addDataToBuffer returns error %d", err);
+        return err;
+    }
+
+    if (!FLAC__stream_decoder_process_until_end_of_metadata(mDecoder)) {
+        if (!FLAC__stream_decoder_reset(mDecoder)) {
+            ALOGE("parseMetadata: failed to reset FLAC stream decoder");
+            return FAILED_TRANSACTION;
+        }
+        mBufferPos = 0;
+        ALOGV("parseMetadata: do not have full metadata blocks yet");
+        return WOULD_BLOCK;
+    }
+
+    if (!mStreamInfoValid) {
+        ALOGE("parseMetadata: missing STREAMINFO");
+        return ERROR_MALFORMED;
+    }
+
+    // check block size
+    if (getMaxBlockSize() == 0) {
+        ALOGE("wrong max blocksize %u", getMaxBlockSize());
+        mStreamInfoValid = false;
+        return ERROR_MALFORMED;
+    }
+
+    // check channel count
+    if (getChannels() == 0 || getChannels() > kMaxChannels) {
+        ALOGE("unsupported channel count %u", getChannels());
+        mStreamInfoValid = false;
+        return ERROR_MALFORMED;
+    }
+
+    // check bit depth
+    switch (getBitsPerSample()) {
+        case 8:
+        case 16:
+        case 24:
+            break;
+
+        default:
+            ALOGE("parseMetadata: unsupported bits per sample %u", getBitsPerSample());
+            mStreamInfoValid = false;
+            return ERROR_MALFORMED;
+    }
+
+    // configure the appropriate copy function, defaulting to trespass
+    static const struct {
+        unsigned mChannels;
+        unsigned mBitsPerSample;
+        void (*mCopy)(short *dst, const int * src[kMaxChannels],
+                unsigned nSamples, unsigned nChannels);
+    } table[] = {
+        { 1,  8, copyMono8     },
+        { 2,  8, copyStereo8   },
+        { 8,  8, copyMultiCh8  },
+        { 1, 16, copyMono16    },
+        { 2, 16, copyStereo16  },
+        { 8, 16, copyMultiCh16 },
+        { 1, 24, copyMono24    },
+        { 2, 24, copyStereo24  },
+        { 8, 24, copyMultiCh24 },
+    };
+    for (const auto &entry : table) {
+        if (entry.mChannels >= getChannels() &&
+                entry.mBitsPerSample == getBitsPerSample()) {
+            mCopy = entry.mCopy;
+            break;
+        }
+    }
+
+    // Now we have all metadata blocks.
+    mBufferPos = 0;
+    mBufferDataSize = 0;
+
+    return OK;
+}
+
+status_t FLACDecoder::decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen,
+        short *outBuffer, size_t *outBufferLen) {
+    ALOGV("decodeOneFrame: input size(%zu)", inBufferLen);
+
+    if (inBufferLen == 0) {
+        ALOGV("decodeOneFrame: no input data");
+        if (outBufferLen) {
+            *outBufferLen = 0;
+        }
+        return OK;
+    }
+
+    if (!mStreamInfoValid) {
+        ALOGW("decodeOneFrame: no streaminfo metadata block");
+    }
+
+    status_t err = addDataToBuffer(inBuffer, inBufferLen);
+    if (err != OK) {
+        ALOGW("decodeOneFrame: addDataToBuffer returns error %d", err);
+        return err;
+    }
+
+    mWriteRequested = true;
+    mWriteCompleted = false;
+    if (!FLAC__stream_decoder_process_single(mDecoder)) {
+        ALOGE("decodeOneFrame: process_single failed");
+        return ERROR_MALFORMED;
+    }
+    if (!mWriteCompleted) {
+        ALOGV("decodeOneFrame: write did not complete");
+        if (outBufferLen) {
+            *outBufferLen = 0;
+        }
+        return OK;
+    }
+
+    // frame header should be consistent with STREAMINFO
+    unsigned blocksize = mWriteHeader.blocksize;
+    if (blocksize == 0 || blocksize > getMaxBlockSize()) {
+        ALOGE("decodeOneFrame: write invalid blocksize %u", blocksize);
+        return ERROR_MALFORMED;
+    }
+    if (mWriteHeader.sample_rate != getSampleRate() ||
+        mWriteHeader.channels != getChannels() ||
+        mWriteHeader.bits_per_sample != getBitsPerSample()) {
+        ALOGE("decodeOneFrame: parameters are changed mid-stream: %d/%d/%d -> %d/%d/%d",
+                getSampleRate(), getChannels(), getBitsPerSample(),
+                mWriteHeader.sample_rate, mWriteHeader.channels, mWriteHeader.bits_per_sample);
+        return ERROR_MALFORMED;
+    }
+    if (mWriteHeader.number_type != FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER) {
+        ALOGE("decodeOneFrame: number type is %d, expected %d",
+                mWriteHeader.number_type, FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+        return ERROR_MALFORMED;
+    }
+
+    size_t bufferSize = blocksize * getChannels() * sizeof(short);
+    if (bufferSize > *outBufferLen) {
+        ALOGW("decodeOneFrame: output buffer holds only partial frame %zu:%zu",
+                *outBufferLen, bufferSize);
+        blocksize = *outBufferLen / (getChannels() * sizeof(short));
+        bufferSize = blocksize * getChannels() * sizeof(short);
+    }
+
+    if (mCopy == nullptr) {
+        ALOGE("decodeOneFrame: format is not supported: channels(%d), BitsPerSample(%d)",
+                getChannels(), getBitsPerSample());
+        return ERROR_UNSUPPORTED;
+    }
+    // copy PCM from FLAC write buffer to output buffer, with interleaving
+    (*mCopy)(outBuffer, mWriteBuffer, blocksize, getChannels());
+    *outBufferLen = bufferSize;
+    return OK;
+}
+
+status_t FLACDecoder::addDataToBuffer(const uint8_t *inBuffer, size_t inBufferLen) {
+    // mBufferPos should be no larger than mBufferDataSize
+    if (inBufferLen > SIZE_MAX - (mBufferDataSize - mBufferPos)) {
+        ALOGE("addDataToBuffer: input buffer is too large");
+        return ERROR_MALFORMED;
+    }
+
+    if (inBufferLen > mBufferLen - mBufferDataSize) {
+        if (mBufferPos > 0) {
+            memmove(mBuffer, mBuffer + mBufferPos, mBufferDataSize - mBufferPos);
+            mBufferDataSize -= mBufferPos;
+            mBufferPos = 0;
+        }
+        if (inBufferLen > mBufferLen - mBufferDataSize) {
+            mBuffer = (uint8_t*)realloc(mBuffer, mBufferDataSize + inBufferLen);
+            if (mBuffer == nullptr) {
+                mBufferDataSize = 0;
+                mBufferLen = 0;
+                ALOGE("decodeOneFrame: failed to allocate memory for input buffer");
+                return NO_MEMORY;
+            }
+            mBufferLen = mBufferDataSize + inBufferLen;
+        }
+    }
+
+    memcpy(mBuffer + mBufferDataSize, inBuffer, inBufferLen);
+    mBufferDataSize += inBufferLen;
+    return OK;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/flac/dec/FLACDecoder.h b/media/libstagefright/flac/dec/FLACDecoder.h
new file mode 100644
index 0000000..36282a8
--- /dev/null
+++ b/media/libstagefright/flac/dec/FLACDecoder.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 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 FLAC_DECODER_H_
+#define FLAC_DECODER_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+#include "FLAC/stream_decoder.h"
+
+namespace android {
+
+// packet based FLAC decoder, wrapps libFLAC stream decoder.
+class FLACDecoder : public RefBase {
+
+public:
+    enum {
+        kMaxChannels = 8,
+    };
+
+    static sp<FLACDecoder> Create();
+
+    FLAC__StreamMetadata_StreamInfo getStreamInfo() const {
+        return mStreamInfo;
+    }
+
+    status_t parseMetadata(const uint8_t *inBuffer, size_t inBufferLen);
+    status_t decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen,
+            short *outBuffer, size_t *outBufferLen);
+    void flush();
+
+protected:
+    FLACDecoder();
+    virtual ~FLACDecoder() override;
+
+private:
+    // stream properties
+    unsigned getMaxBlockSize() const {
+        return mStreamInfo.max_blocksize;
+    }
+    unsigned getSampleRate() const {
+        return mStreamInfo.sample_rate;
+    }
+    unsigned getChannels() const {
+        return mStreamInfo.channels;
+    }
+    unsigned getBitsPerSample() const {
+        return mStreamInfo.bits_per_sample;
+    }
+    FLAC__uint64 getTotalSamples() const {
+        return mStreamInfo.total_samples;
+    }
+
+    status_t addDataToBuffer(const uint8_t *inBuffer, size_t inBufferLen);
+
+    FLAC__StreamDecoder *mDecoder;
+
+    uint8_t *mBuffer;  // cache input bit stream data
+    size_t mBufferLen;  // the memory size of |mBuffer|
+    size_t mBufferPos;  // next byte to read in |mBuffer|
+    // size of input data stored in |mBuffer|, always started at offset 0
+    size_t mBufferDataSize;
+
+    // cached when the STREAMINFO metadata is parsed by libFLAC
+    FLAC__StreamMetadata_StreamInfo mStreamInfo;
+    bool mStreamInfoValid;
+
+    // cached when a decoded PCM block is "written" by libFLAC decoder
+    bool mWriteRequested;
+    bool mWriteCompleted;
+    FLAC__FrameHeader mWriteHeader;
+    FLAC__int32 const * mWriteBuffer[kMaxChannels];
+
+    // most recent error reported by libFLAC decoder
+    FLAC__StreamDecoderErrorStatus mErrorStatus;
+
+    void (*mCopy)(short *dst, const int *src[kMaxChannels], unsigned nSamples, unsigned nChannels);
+
+    status_t init();
+
+    // FLAC stream decoder callbacks as C++ instance methods
+    FLAC__StreamDecoderReadStatus readCallback(FLAC__byte buffer[], size_t *bytes);
+    FLAC__StreamDecoderWriteStatus writeCallback(
+            const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+    void metadataCallback(const FLAC__StreamMetadata *metadata);
+    void errorCallback(FLAC__StreamDecoderErrorStatus status);
+
+    DISALLOW_EVIL_CONSTRUCTORS(FLACDecoder);
+};
+
+}  // namespace android
+
+#endif  // FLAC_DECODER_H_
diff --git a/media/libstagefright/flac/dec/MODULE_LICENSE_APACHE2 b/media/libstagefright/flac/dec/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libstagefright/flac/dec/MODULE_LICENSE_APACHE2
diff --git a/media/libstagefright/flac/dec/NOTICE b/media/libstagefright/flac/dec/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/media/libstagefright/flac/dec/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 2f6c054..eeeb284 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -1,7 +1,4 @@
-cc_library_shared {
-    name: "libstagefright_foundation",
-
-    srcs: [
+COMMON_SRCS = [
         "AAtomizer.cpp",
         "ABitReader.cpp",
         "ABuffer.cpp",
@@ -14,7 +11,6 @@
         "ANetworkSession.cpp",
         "AString.cpp",
         "AStringUtils.cpp",
-        "AWakeLock.cpp",
         "ColorUtils.cpp",
         "MediaBuffer.cpp",
         "MediaBufferGroup.cpp",
@@ -22,19 +18,34 @@
         "ParsedMessage.cpp",
         "base64.cpp",
         "hexdump.cpp",
-    ],
+]
 
-    include_dirs: ["frameworks/av/include/media/stagefright/foundation"],
-
-    export_include_dirs: ["include"],
-
-    shared_libs: [
+COMMON_LIBS = [
         "libbinder",
         "libutils",
         "libui",
         "libcutils",
         "liblog",
-        "libpowermanager",
+]
+
+cc_defaults {
+    name: "libstagefright_foundation-defaults",
+
+    include_dirs: [
+        "frameworks/av/include",
+        "frameworks/native/include",
+    ],
+
+    local_include_dirs: [
+        "include/media/stagefright/foundation",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    header_libs: [
+        "libhardware_headers",
     ],
 
     export_shared_lib_headers: [
@@ -47,7 +58,9 @@
         "-Werror",
         "-Wall",
     ],
+
     clang: true,
+
     sanitize: {
         misc_undefined: [
             "unsigned-integer-overflow",
@@ -59,3 +72,20 @@
         },
     },
 }
+
+cc_library_shared {
+    name: "libstagefright_foundation",
+    defaults: ["libstagefright_foundation-defaults"],
+
+    srcs: COMMON_SRCS + ["AWakeLock.cpp"],
+    shared_libs: COMMON_LIBS + ["libpowermanager"],
+}
+
+cc_library_shared {
+    name: "libstagefright_foundation_vendor",
+    defaults: ["libstagefright_foundation-defaults"],
+    vendor: true,
+
+    srcs: COMMON_SRCS,
+    shared_libs: COMMON_LIBS,
+}
diff --git a/media/libstagefright/foundation/include b/media/libstagefright/foundation/include
deleted file mode 120000
index 3a1af68..0000000
--- a/media/libstagefright/foundation/include
+++ /dev/null
@@ -1 +0,0 @@
-../include/
\ No newline at end of file
diff --git a/media/libstagefright/include/foundation/AAtomizer.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AAtomizer.h
similarity index 100%
rename from media/libstagefright/include/foundation/AAtomizer.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AAtomizer.h
diff --git a/media/libstagefright/include/foundation/ABase.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ABase.h
similarity index 100%
rename from media/libstagefright/include/foundation/ABase.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ABase.h
diff --git a/media/libstagefright/include/foundation/ABitReader.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ABitReader.h
similarity index 100%
rename from media/libstagefright/include/foundation/ABitReader.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ABitReader.h
diff --git a/media/libstagefright/include/foundation/ABuffer.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ABuffer.h
similarity index 100%
rename from media/libstagefright/include/foundation/ABuffer.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ABuffer.h
diff --git a/media/libstagefright/include/foundation/AData.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
similarity index 100%
rename from media/libstagefright/include/foundation/AData.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
diff --git a/media/libstagefright/include/foundation/ADebug.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h
similarity index 100%
rename from media/libstagefright/include/foundation/ADebug.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h
diff --git a/media/libstagefright/include/foundation/AHandler.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AHandler.h
similarity index 100%
rename from media/libstagefright/include/foundation/AHandler.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AHandler.h
diff --git a/media/libstagefright/include/foundation/AHandlerReflector.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AHandlerReflector.h
similarity index 100%
rename from media/libstagefright/include/foundation/AHandlerReflector.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AHandlerReflector.h
diff --git a/media/libstagefright/include/foundation/AHierarchicalStateMachine.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AHierarchicalStateMachine.h
similarity index 100%
rename from media/libstagefright/include/foundation/AHierarchicalStateMachine.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AHierarchicalStateMachine.h
diff --git a/media/libstagefright/include/foundation/ALookup.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ALookup.h
similarity index 100%
rename from media/libstagefright/include/foundation/ALookup.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ALookup.h
diff --git a/media/libstagefright/include/foundation/ALooper.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ALooper.h
similarity index 100%
rename from media/libstagefright/include/foundation/ALooper.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ALooper.h
diff --git a/media/libstagefright/include/foundation/ALooperRoster.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ALooperRoster.h
similarity index 100%
rename from media/libstagefright/include/foundation/ALooperRoster.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ALooperRoster.h
diff --git a/media/libstagefright/include/foundation/AMessage.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
similarity index 100%
rename from media/libstagefright/include/foundation/AMessage.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
diff --git a/media/libstagefright/include/foundation/ANetworkSession.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ANetworkSession.h
similarity index 100%
rename from media/libstagefright/include/foundation/ANetworkSession.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ANetworkSession.h
diff --git a/media/libstagefright/include/foundation/AString.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AString.h
similarity index 100%
rename from media/libstagefright/include/foundation/AString.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AString.h
diff --git a/media/libstagefright/include/foundation/AStringUtils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AStringUtils.h
similarity index 100%
rename from media/libstagefright/include/foundation/AStringUtils.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AStringUtils.h
diff --git a/media/libstagefright/include/foundation/AUtils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AUtils.h
similarity index 100%
rename from media/libstagefright/include/foundation/AUtils.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AUtils.h
diff --git a/media/libstagefright/include/foundation/AWakeLock.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AWakeLock.h
similarity index 100%
rename from media/libstagefright/include/foundation/AWakeLock.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/AWakeLock.h
diff --git a/media/libstagefright/include/foundation/ColorUtils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h
similarity index 100%
rename from media/libstagefright/include/foundation/ColorUtils.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h
diff --git a/media/libstagefright/include/foundation/FileDescriptor.h b/media/libstagefright/foundation/include/media/stagefright/foundation/FileDescriptor.h
similarity index 100%
rename from media/libstagefright/include/foundation/FileDescriptor.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/FileDescriptor.h
diff --git a/media/libstagefright/include/foundation/Flagged.h b/media/libstagefright/foundation/include/media/stagefright/foundation/Flagged.h
similarity index 100%
rename from media/libstagefright/include/foundation/Flagged.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/Flagged.h
diff --git a/media/libstagefright/include/foundation/MediaBufferBase.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaBufferBase.h
similarity index 100%
rename from media/libstagefright/include/foundation/MediaBufferBase.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/MediaBufferBase.h
diff --git a/media/libstagefright/include/foundation/Mutexed.h b/media/libstagefright/foundation/include/media/stagefright/foundation/Mutexed.h
similarity index 100%
rename from media/libstagefright/include/foundation/Mutexed.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/Mutexed.h
diff --git a/media/libstagefright/include/foundation/ParsedMessage.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ParsedMessage.h
similarity index 100%
rename from media/libstagefright/include/foundation/ParsedMessage.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/ParsedMessage.h
diff --git a/media/libstagefright/include/foundation/TypeTraits.h b/media/libstagefright/foundation/include/media/stagefright/foundation/TypeTraits.h
similarity index 100%
rename from media/libstagefright/include/foundation/TypeTraits.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/TypeTraits.h
diff --git a/media/libstagefright/include/foundation/base64.h b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
similarity index 100%
rename from media/libstagefright/include/foundation/base64.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
diff --git a/media/libstagefright/include/foundation/hexdump.h b/media/libstagefright/foundation/include/media/stagefright/foundation/hexdump.h
similarity index 100%
rename from media/libstagefright/include/foundation/hexdump.h
rename to media/libstagefright/foundation/include/media/stagefright/foundation/hexdump.h
diff --git a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
index b43635d..db5496a 100644
--- a/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
+++ b/media/libstagefright/include/SoftVideoEncoderOMXComponent.h
@@ -21,7 +21,6 @@
 #include <media/IOMX.h>
 
 #include "SimpleSoftOMXComponent.h"
-#include <system/window.h>
 
 struct hw_module_t;
 
diff --git a/media/libstagefright/include/AACWriter.h b/media/libstagefright/include/media/stagefright/AACWriter.h
similarity index 100%
rename from media/libstagefright/include/AACWriter.h
rename to media/libstagefright/include/media/stagefright/AACWriter.h
diff --git a/media/libstagefright/include/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
similarity index 99%
rename from media/libstagefright/include/ACodec.h
rename to media/libstagefright/include/media/stagefright/ACodec.h
index 22b8657..d049df5 100644
--- a/media/libstagefright/include/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -15,7 +15,6 @@
  */
 
 #ifndef A_CODEC_H_
-
 #define A_CODEC_H_
 
 #include <stdint.h>
@@ -30,6 +29,7 @@
 #include <utils/NativeHandle.h>
 #include <OMX_Audio.h>
 #include <hardware/gralloc.h>
+#include <nativebase/nativebase.h>
 
 #define TRACK_BUFFER_TIMING     0
 
diff --git a/media/libstagefright/include/AMRWriter.h b/media/libstagefright/include/media/stagefright/AMRWriter.h
similarity index 100%
rename from media/libstagefright/include/AMRWriter.h
rename to media/libstagefright/include/media/stagefright/AMRWriter.h
diff --git a/media/libstagefright/include/AudioPlayer.h b/media/libstagefright/include/media/stagefright/AudioPlayer.h
similarity index 100%
rename from media/libstagefright/include/AudioPlayer.h
rename to media/libstagefright/include/media/stagefright/AudioPlayer.h
diff --git a/media/libstagefright/include/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h
similarity index 96%
rename from media/libstagefright/include/AudioSource.h
rename to media/libstagefright/include/media/stagefright/AudioSource.h
index f20c2cd..07a51bf 100644
--- a/media/libstagefright/include/AudioSource.h
+++ b/media/libstagefright/include/media/stagefright/AudioSource.h
@@ -53,6 +53,7 @@
 
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
+    virtual status_t setStopTimeUs(int64_t stopTimeUs);
 
     status_t dataCallback(const AudioRecord::Buffer& buffer);
     virtual void signalBufferReturned(MediaBuffer *buffer);
@@ -85,6 +86,8 @@
 
     bool mTrackMaxAmplitude;
     int64_t mStartTimeUs;
+    int64_t mStopSystemTimeUs;
+    int64_t mLastFrameTimestampUs;
     int16_t mMaxAmplitude;
     int64_t mPrevSampleTimeUs;
     int64_t mInitialReadTimeUs;
diff --git a/media/libstagefright/include/BufferProducerWrapper.h b/media/libstagefright/include/media/stagefright/BufferProducerWrapper.h
similarity index 100%
rename from media/libstagefright/include/BufferProducerWrapper.h
rename to media/libstagefright/include/media/stagefright/BufferProducerWrapper.h
diff --git a/media/libstagefright/include/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h
similarity index 99%
rename from media/libstagefright/include/CameraSource.h
rename to media/libstagefright/include/media/stagefright/CameraSource.h
index aa56d27..2aaa884 100644
--- a/media/libstagefright/include/CameraSource.h
+++ b/media/libstagefright/include/media/stagefright/CameraSource.h
@@ -98,6 +98,7 @@
     virtual status_t stop() { return reset(); }
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL);
+    virtual status_t setStopTimeUs(int64_t stopTimeUs);
 
     /**
      * Check whether a CameraSource object is properly initialized.
@@ -253,6 +254,7 @@
     List<int64_t> mFrameTimes;
 
     int64_t mFirstFrameTimeUs;
+    int64_t mStopSystemTimeUs;
     int32_t mNumFramesDropped;
     int32_t mNumGlitches;
     int64_t mGlitchDurationThresholdUs;
diff --git a/media/libstagefright/include/CameraSourceTimeLapse.h b/media/libstagefright/include/media/stagefright/CameraSourceTimeLapse.h
similarity index 100%
rename from media/libstagefright/include/CameraSourceTimeLapse.h
rename to media/libstagefright/include/media/stagefright/CameraSourceTimeLapse.h
diff --git a/media/libstagefright/include/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
similarity index 100%
rename from media/libstagefright/include/CodecBase.h
rename to media/libstagefright/include/media/stagefright/CodecBase.h
diff --git a/media/libstagefright/include/ColorConverter.h b/media/libstagefright/include/media/stagefright/ColorConverter.h
similarity index 100%
rename from media/libstagefright/include/ColorConverter.h
rename to media/libstagefright/include/media/stagefright/ColorConverter.h
diff --git a/media/libstagefright/include/DataSource.h b/media/libstagefright/include/media/stagefright/DataSource.h
similarity index 100%
rename from media/libstagefright/include/DataSource.h
rename to media/libstagefright/include/media/stagefright/DataSource.h
diff --git a/media/libstagefright/include/DataURISource.h b/media/libstagefright/include/media/stagefright/DataURISource.h
similarity index 100%
rename from media/libstagefright/include/DataURISource.h
rename to media/libstagefright/include/media/stagefright/DataURISource.h
diff --git a/media/libstagefright/include/DataUriSource.h b/media/libstagefright/include/media/stagefright/DataUriSource.h
similarity index 100%
rename from media/libstagefright/include/DataUriSource.h
rename to media/libstagefright/include/media/stagefright/DataUriSource.h
diff --git a/media/libstagefright/include/FileSource.h b/media/libstagefright/include/media/stagefright/FileSource.h
similarity index 100%
rename from media/libstagefright/include/FileSource.h
rename to media/libstagefright/include/media/stagefright/FileSource.h
diff --git a/media/libstagefright/include/FrameRenderTracker.h b/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
similarity index 99%
rename from media/libstagefright/include/FrameRenderTracker.h
rename to media/libstagefright/include/media/stagefright/FrameRenderTracker.h
index 6cbf85d..044699c 100644
--- a/media/libstagefright/include/FrameRenderTracker.h
+++ b/media/libstagefright/include/media/stagefright/FrameRenderTracker.h
@@ -20,13 +20,14 @@
 
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
-#include <system/window.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AString.h>
 
 #include <list>
 
+struct ANativeWindowBuffer;
+
 namespace android {
 
 class Fence;
diff --git a/media/libstagefright/include/JPEGSource.h b/media/libstagefright/include/media/stagefright/JPEGSource.h
similarity index 100%
rename from media/libstagefright/include/JPEGSource.h
rename to media/libstagefright/include/media/stagefright/JPEGSource.h
diff --git a/media/libstagefright/include/MPEG2TSWriter.h b/media/libstagefright/include/media/stagefright/MPEG2TSWriter.h
similarity index 100%
rename from media/libstagefright/include/MPEG2TSWriter.h
rename to media/libstagefright/include/media/stagefright/MPEG2TSWriter.h
diff --git a/media/libstagefright/include/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
similarity index 100%
rename from media/libstagefright/include/MPEG4Writer.h
rename to media/libstagefright/include/media/stagefright/MPEG4Writer.h
diff --git a/media/libstagefright/include/MediaAdapter.h b/media/libstagefright/include/media/stagefright/MediaAdapter.h
similarity index 100%
rename from media/libstagefright/include/MediaAdapter.h
rename to media/libstagefright/include/media/stagefright/MediaAdapter.h
diff --git a/media/libstagefright/include/MediaBuffer.h b/media/libstagefright/include/media/stagefright/MediaBuffer.h
similarity index 100%
rename from media/libstagefright/include/MediaBuffer.h
rename to media/libstagefright/include/media/stagefright/MediaBuffer.h
diff --git a/media/libstagefright/include/MediaBufferGroup.h b/media/libstagefright/include/media/stagefright/MediaBufferGroup.h
similarity index 100%
rename from media/libstagefright/include/MediaBufferGroup.h
rename to media/libstagefright/include/media/stagefright/MediaBufferGroup.h
diff --git a/media/libstagefright/include/MediaClock.h b/media/libstagefright/include/media/stagefright/MediaClock.h
similarity index 100%
rename from media/libstagefright/include/MediaClock.h
rename to media/libstagefright/include/media/stagefright/MediaClock.h
diff --git a/media/libstagefright/include/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
similarity index 100%
rename from media/libstagefright/include/MediaCodec.h
rename to media/libstagefright/include/media/stagefright/MediaCodec.h
diff --git a/media/libstagefright/include/MediaCodecList.h b/media/libstagefright/include/media/stagefright/MediaCodecList.h
similarity index 100%
rename from media/libstagefright/include/MediaCodecList.h
rename to media/libstagefright/include/media/stagefright/MediaCodecList.h
diff --git a/media/libstagefright/include/MediaCodecSource.h b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
similarity index 92%
rename from media/libstagefright/include/MediaCodecSource.h
rename to media/libstagefright/include/media/stagefright/MediaCodecSource.h
index 02ba227..3ac539e 100644
--- a/media/libstagefright/include/MediaCodecSource.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
@@ -60,6 +60,8 @@
     virtual status_t read(
             MediaBuffer **buffer,
             const ReadOptions *options = NULL);
+    virtual status_t setStopTimeUs(int64_t stopTimeUs);
+
 
     // MediaBufferObserver
     virtual void signalBufferReturned(MediaBuffer *buffer);
@@ -67,11 +69,7 @@
     // for AHandlerReflector
     void onMessageReceived(const sp<AMessage> &msg);
 
-    // Set GraphicBufferSource stop time. GraphicBufferSource will stop
-    // after receiving a buffer with timestamp larger or equal than stopTimeUs.
-    // All the buffers with timestamp larger or equal to stopTimeUs will be
-    // discarded. stopTimeUs uses SYSTEM_TIME_MONOTONIC time base.
-    status_t setStopStimeUs(int64_t stopTimeUs);
+
 
 protected:
     virtual ~MediaCodecSource();
@@ -86,7 +84,7 @@
         kWhatStop,
         kWhatPause,
         kWhatSetInputBufferTimeOffset,
-        kWhatSetStopTimeOffset,
+        kWhatSetStopTimeUs,
         kWhatGetFirstSampleSystemTimeUs,
         kWhatStopStalled,
     };
diff --git a/media/libstagefright/include/MediaDefs.h b/media/libstagefright/include/media/stagefright/MediaDefs.h
similarity index 100%
rename from media/libstagefright/include/MediaDefs.h
rename to media/libstagefright/include/media/stagefright/MediaDefs.h
diff --git a/media/libstagefright/include/MediaErrors.h b/media/libstagefright/include/media/stagefright/MediaErrors.h
similarity index 100%
rename from media/libstagefright/include/MediaErrors.h
rename to media/libstagefright/include/media/stagefright/MediaErrors.h
diff --git a/media/libstagefright/include/MediaExtractor.h b/media/libstagefright/include/media/stagefright/MediaExtractor.h
similarity index 100%
rename from media/libstagefright/include/MediaExtractor.h
rename to media/libstagefright/include/media/stagefright/MediaExtractor.h
diff --git a/media/libstagefright/include/MediaFilter.h b/media/libstagefright/include/media/stagefright/MediaFilter.h
similarity index 100%
rename from media/libstagefright/include/MediaFilter.h
rename to media/libstagefright/include/media/stagefright/MediaFilter.h
diff --git a/media/libstagefright/include/MediaHTTP.h b/media/libstagefright/include/media/stagefright/MediaHTTP.h
similarity index 100%
rename from media/libstagefright/include/MediaHTTP.h
rename to media/libstagefright/include/media/stagefright/MediaHTTP.h
diff --git a/media/libstagefright/include/MediaMuxer.h b/media/libstagefright/include/media/stagefright/MediaMuxer.h
similarity index 100%
rename from media/libstagefright/include/MediaMuxer.h
rename to media/libstagefright/include/media/stagefright/MediaMuxer.h
diff --git a/media/libstagefright/include/MediaSource.h b/media/libstagefright/include/media/stagefright/MediaSource.h
similarity index 73%
rename from media/libstagefright/include/MediaSource.h
rename to media/libstagefright/include/media/stagefright/MediaSource.h
index 1bd3ed0..14adb05 100644
--- a/media/libstagefright/include/MediaSource.h
+++ b/media/libstagefright/include/media/stagefright/MediaSource.h
@@ -75,6 +75,23 @@
         return ERROR_UNSUPPORTED;
     }
 
+    // The consumer of this media source requests the source stops sending
+    // buffers with timestamp larger than or equal to stopTimeUs. stopTimeUs
+    // must be in the same time base as the startTime passed in start(). If
+    // source does not support this request, ERROR_UNSUPPORTED will be returned.
+    // If stopTimeUs is invalid, BAD_VALUE will be returned. This could be
+    // called at any time even before source starts and it could be called
+    // multiple times. Setting stopTimeUs to be -1 will effectively cancel the stopTimeUs
+    // set previously. If stopTimeUs is larger than or equal to last buffer's timestamp,
+    // source will start to drop buffer when it gets a buffer with timestamp larger
+    // than or equal to stopTimeUs. If stopTimeUs is smaller than or equal to last
+    // buffer's timestamp, source will drop all the incoming buffers immediately.
+    // After setting stopTimeUs, source may still stop sending buffers with timestamp
+    // less than stopTimeUs if it is stopped by the consumer.
+    virtual status_t setStopTimeUs(int64_t /* stopTimeUs */) {
+        return ERROR_UNSUPPORTED;
+    }
+
 protected:
     virtual ~MediaSource();
 
diff --git a/media/libstagefright/include/MediaSync.h b/media/libstagefright/include/media/stagefright/MediaSync.h
similarity index 100%
rename from media/libstagefright/include/MediaSync.h
rename to media/libstagefright/include/media/stagefright/MediaSync.h
diff --git a/media/libstagefright/include/MediaWriter.h b/media/libstagefright/include/media/stagefright/MediaWriter.h
similarity index 100%
rename from media/libstagefright/include/MediaWriter.h
rename to media/libstagefright/include/media/stagefright/MediaWriter.h
diff --git a/media/libstagefright/include/MetaData.h b/media/libstagefright/include/media/stagefright/MetaData.h
similarity index 99%
rename from media/libstagefright/include/MetaData.h
rename to media/libstagefright/include/media/stagefright/MetaData.h
index 7afd22d..9676b97 100644
--- a/media/libstagefright/include/MetaData.h
+++ b/media/libstagefright/include/media/stagefright/MetaData.h
@@ -64,6 +64,7 @@
     kKeyOpusHeader        = 'ohdr',  // raw data
     kKeyOpusCodecDelay    = 'ocod',  // uint64_t (codec delay in ns)
     kKeyOpusSeekPreRoll   = 'ospr',  // uint64_t (seek preroll in ns)
+    kKeyFlacMetadata      = 'flMd',  // raw data
     kKeyVp9CodecPrivate   = 'vp9p',  // raw data (vp9 csd information)
     kKeyWantsNALFragments = 'NALf',
     kKeyIsSyncFrame       = 'sync',  // int32_t (bool)
diff --git a/media/libstagefright/include/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
similarity index 100%
rename from media/libstagefright/include/NuMediaExtractor.h
rename to media/libstagefright/include/media/stagefright/NuMediaExtractor.h
diff --git a/media/libstagefright/include/OMXClient.h b/media/libstagefright/include/media/stagefright/OMXClient.h
similarity index 100%
rename from media/libstagefright/include/OMXClient.h
rename to media/libstagefright/include/media/stagefright/OMXClient.h
diff --git a/media/libstagefright/include/PersistentSurface.h b/media/libstagefright/include/media/stagefright/PersistentSurface.h
similarity index 100%
rename from media/libstagefright/include/PersistentSurface.h
rename to media/libstagefright/include/media/stagefright/PersistentSurface.h
diff --git a/media/libstagefright/include/ProcessInfo.h b/media/libstagefright/include/media/stagefright/ProcessInfo.h
similarity index 100%
rename from media/libstagefright/include/ProcessInfo.h
rename to media/libstagefright/include/media/stagefright/ProcessInfo.h
diff --git a/media/libstagefright/include/ProcessInfoInterface.h b/media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
similarity index 100%
rename from media/libstagefright/include/ProcessInfoInterface.h
rename to media/libstagefright/include/media/stagefright/ProcessInfoInterface.h
diff --git a/media/libstagefright/include/RemoteDataSource.h b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
similarity index 100%
rename from media/libstagefright/include/RemoteDataSource.h
rename to media/libstagefright/include/media/stagefright/RemoteDataSource.h
diff --git a/media/libstagefright/include/RenderScriptWrapper.h b/media/libstagefright/include/media/stagefright/RenderScriptWrapper.h
similarity index 100%
rename from media/libstagefright/include/RenderScriptWrapper.h
rename to media/libstagefright/include/media/stagefright/RenderScriptWrapper.h
diff --git a/media/libstagefright/include/SimpleDecodingSource.h b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
similarity index 93%
rename from media/libstagefright/include/SimpleDecodingSource.h
rename to media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
index e6aee6a..a000fde 100644
--- a/media/libstagefright/include/SimpleDecodingSource.h
+++ b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
@@ -17,8 +17,6 @@
 #ifndef SIMPLE_DECODING_SOURCE_H_
 #define SIMPLE_DECODING_SOURCE_H_
 
-#include <system/window.h>
-
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/foundation/AString.h>
 #include <media/stagefright/foundation/Mutexed.h>
@@ -26,6 +24,8 @@
 #include <utils/Condition.h>
 #include <utils/StrongPointer.h>
 
+struct ANativeWindow;
+
 namespace android {
 
 struct ALooper;
@@ -45,10 +45,13 @@
     // does not support secure input or pausing.
     // if |desiredCodec| is given, use this specific codec.
     static sp<SimpleDecodingSource> Create(
-            const sp<IMediaSource> &source, uint32_t flags = 0,
-            const sp<ANativeWindow> &nativeWindow = NULL,
+            const sp<IMediaSource> &source, uint32_t flags,
+            const sp<ANativeWindow> &nativeWindow,
             const char *desiredCodec = NULL);
 
+    static sp<SimpleDecodingSource> Create(
+            const sp<IMediaSource> &source, uint32_t flags = 0);
+
     virtual ~SimpleDecodingSource();
 
     // starts this source (and it's underlying source). |params| is ignored.
diff --git a/media/libstagefright/include/SkipCutBuffer.h b/media/libstagefright/include/media/stagefright/SkipCutBuffer.h
similarity index 100%
rename from media/libstagefright/include/SkipCutBuffer.h
rename to media/libstagefright/include/media/stagefright/SkipCutBuffer.h
diff --git a/media/libstagefright/include/StagefrightMediaScanner.h b/media/libstagefright/include/media/stagefright/StagefrightMediaScanner.h
similarity index 100%
rename from media/libstagefright/include/StagefrightMediaScanner.h
rename to media/libstagefright/include/media/stagefright/StagefrightMediaScanner.h
diff --git a/media/libstagefright/include/SurfaceMediaSource.h b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
similarity index 100%
rename from media/libstagefright/include/SurfaceMediaSource.h
rename to media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
diff --git a/media/libstagefright/include/SurfaceUtils.h b/media/libstagefright/include/media/stagefright/SurfaceUtils.h
similarity index 100%
rename from media/libstagefright/include/SurfaceUtils.h
rename to media/libstagefright/include/media/stagefright/SurfaceUtils.h
diff --git a/media/libstagefright/include/Utils.h b/media/libstagefright/include/media/stagefright/Utils.h
similarity index 100%
rename from media/libstagefright/include/Utils.h
rename to media/libstagefright/include/media/stagefright/Utils.h
diff --git a/media/libstagefright/include/VideoFrameScheduler.h b/media/libstagefright/include/media/stagefright/VideoFrameScheduler.h
similarity index 100%
rename from media/libstagefright/include/VideoFrameScheduler.h
rename to media/libstagefright/include/media/stagefright/VideoFrameScheduler.h
diff --git a/media/libstagefright/include/YUVCanvas.h b/media/libstagefright/include/media/stagefright/YUVCanvas.h
similarity index 100%
rename from media/libstagefright/include/YUVCanvas.h
rename to media/libstagefright/include/media/stagefright/YUVCanvas.h
diff --git a/media/libstagefright/include/YUVImage.h b/media/libstagefright/include/media/stagefright/YUVImage.h
similarity index 100%
rename from media/libstagefright/include/YUVImage.h
rename to media/libstagefright/include/media/stagefright/YUVImage.h
diff --git a/media/libstagefright/include/media/stagefright/foundation b/media/libstagefright/include/media/stagefright/foundation
new file mode 120000
index 0000000..b9fd3b3
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/foundation
@@ -0,0 +1 @@
+../../../foundation/include/media/stagefright/foundation/
\ No newline at end of file
diff --git a/media/libstagefright/matroska/Android.bp b/media/libstagefright/matroska/Android.bp
index a5891c3..ec2fb4b 100644
--- a/media/libstagefright/matroska/Android.bp
+++ b/media/libstagefright/matroska/Android.bp
@@ -4,8 +4,10 @@
     srcs: ["MatroskaExtractor.cpp"],
 
     include_dirs: [
+        "external/flac/include",
         "external/libvpx/libwebm",
         "frameworks/native/include/media/openmax",
+        "frameworks/av/media/libstagefright/flac/dec",
         "frameworks/av/media/libstagefright/include",
     ],
 
@@ -26,5 +28,8 @@
         },
     },
 
-    shared_libs: ["libmedia"],
+    shared_libs: [
+        "libmedia",
+        "libstagefright_flacdec"
+    ],
 }
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 81179d1..813a257 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "MatroskaExtractor"
 #include <utils/Log.h>
 
+#include "FLACDecoder.h"
 #include "MatroskaExtractor.h"
 #include "avc_utils.h"
 
@@ -1051,6 +1052,37 @@
     return OK;
 }
 
+static status_t addFlacMetadata(
+        const sp<MetaData> &meta,
+        const void *codecPrivate, size_t codecPrivateSize) {
+    // hexdump(codecPrivate, codecPrivateSize);
+
+    meta->setData(kKeyFlacMetadata, 0, codecPrivate, codecPrivateSize);
+
+    int32_t maxInputSize = 64 << 10;
+    sp<FLACDecoder> flacDecoder = FLACDecoder::Create();
+    if (flacDecoder != NULL
+            && flacDecoder->parseMetadata((const uint8_t*)codecPrivate, codecPrivateSize) == OK) {
+        FLAC__StreamMetadata_StreamInfo streamInfo = flacDecoder->getStreamInfo();
+        maxInputSize = streamInfo.max_framesize;
+        if (maxInputSize == 0) {
+            // In case max framesize is not available, use raw data size as max framesize,
+            // assuming there is no expansion.
+            if (streamInfo.max_blocksize != 0
+                    && streamInfo.channels != 0
+                    && ((streamInfo.bits_per_sample + 7) / 8) >
+                        INT32_MAX / streamInfo.max_blocksize / streamInfo.channels) {
+                return ERROR_MALFORMED;
+            }
+            maxInputSize = ((streamInfo.bits_per_sample + 7) / 8)
+                * streamInfo.max_blocksize * streamInfo.channels;
+        }
+    }
+    meta->setInt32(kKeyMaxInputSize, maxInputSize);
+
+    return OK;
+}
+
 status_t MatroskaExtractor::synthesizeAVCC(TrackInfo *trackInfo, size_t index) {
     BlockIterator iter(this, trackInfo->mTrackNum, index);
     if (iter.eos()) {
@@ -1363,6 +1395,9 @@
                     mSeekPreRollNs = track->GetSeekPreRoll();
                 } else if (!strcmp("A_MPEG/L3", codecID)) {
                     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+                } else if (!strcmp("A_FLAC", codecID)) {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_FLAC);
+                    err = addFlacMetadata(meta, codecPrivate, codecPrivateSize);
                 } else {
                     ALOGW("%s is not supported.", codecID);
                     continue;
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp b/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
index 650db8e..acda060 100644
--- a/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
+++ b/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
@@ -21,6 +21,7 @@
 #include "WGraphicBufferProducer.h"
 #include "WProducerListener.h"
 #include "Conversion.h"
+#include <system/window.h>
 
 namespace android {
 namespace hardware {
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
index e876306..d8540f8 100644
--- a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
@@ -206,8 +206,10 @@
 
 Return<void> TWGraphicBufferSource::getStopTimeOffsetUs(
         getStopTimeOffsetUs_cb _hidl_cb) {
-    // TODO: Implement this when needed.
-    _hidl_cb(Status::OK, 0);
+    status_t status;
+    int64_t stopTimeOffsetUs;
+    status = mBase->getStopTimeOffsetUs(&stopTimeOffsetUs);
+    _hidl_cb(toStatus(status), stopTimeOffsetUs);
     return Void();
 }
 
diff --git a/media/libstagefright/omx/BWGraphicBufferSource.cpp b/media/libstagefright/omx/BWGraphicBufferSource.cpp
index 2e2c461..79f6d93 100644
--- a/media/libstagefright/omx/BWGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/BWGraphicBufferSource.cpp
@@ -160,6 +160,11 @@
     return Status::fromStatusT(mBase->setStopTimeUs(stopTimeUs));
 }
 
+::android::binder::Status BWGraphicBufferSource::getStopTimeOffsetUs(
+        int64_t *stopTimeOffsetUs) {
+    return Status::fromStatusT(mBase->getStopTimeOffsetUs(stopTimeOffsetUs));
+}
+
 ::android::binder::Status BWGraphicBufferSource::setColorAspects(
         int32_t aspects) {
     return Status::fromStatusT(mBase->setColorAspects(aspects));
diff --git a/media/libstagefright/omx/BWGraphicBufferSource.h b/media/libstagefright/omx/BWGraphicBufferSource.h
index 6f69d39..0f78eb6 100644
--- a/media/libstagefright/omx/BWGraphicBufferSource.h
+++ b/media/libstagefright/omx/BWGraphicBufferSource.h
@@ -53,6 +53,7 @@
             double fps, double captureFps) override;
     Status setStartTimeUs(int64_t startTimeUs) override;
     Status setStopTimeUs(int64_t stopTimeUs) override;
+    Status getStopTimeOffsetUs(int64_t* stopTimeOffsetUs) override;
     Status setColorAspects(int32_t aspects) override;
     Status setTimeOffsetUs(int64_t timeOffsetsUs) override;
     Status signalEndOfInputStream() override;
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index bc02738..2f6fec8 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -264,6 +264,7 @@
     mLastDataspace(HAL_DATASPACE_UNKNOWN),
     mExecuting(false),
     mSuspended(false),
+    mLastFrameTimestampUs(-1),
     mStopTimeUs(-1),
     mLastActionTimeUs(-1ll),
     mSkipFramesBeforeNs(-1ll),
@@ -649,6 +650,7 @@
         }
         ALOGV("buffer submitted [slot=%d, useCount=%ld] acquired=%d",
                 item.mBuffer->getSlot(), item.mBuffer.use_count(), mNumOutstandingAcquires);
+        mLastFrameTimestampUs = itemTimeUs;
     }
 
     return true;
@@ -1220,10 +1222,20 @@
     return OK;
 }
 
+status_t GraphicBufferSource::getStopTimeOffsetUs(int64_t *stopTimeOffsetUs) {
+    ALOGV("getStopTimeOffsetUs");
+    Mutex::Autolock autoLock(mMutex);
+    if (mStopTimeUs == -1) {
+        ALOGW("Fail to return stopTimeOffsetUs as stop time is not set");
+        return INVALID_OPERATION;
+    }
+    *stopTimeOffsetUs = mStopTimeUs - mLastFrameTimestampUs;
+    return OK;
+}
+
 status_t GraphicBufferSource::setTimeLapseConfig(double fps, double captureFps) {
     ALOGV("setTimeLapseConfig: fps=%lg, captureFps=%lg",
             fps, captureFps);
-
     Mutex::Autolock autoLock(mMutex);
 
     if (mExecuting || !(fps > 0) || !(captureFps > 0)) {
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 3df1aa1..29b51a8 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -172,6 +172,13 @@
     // and not submitted to encoder. timeUs uses SYSTEM_TIME_MONOTONIC time base.
     status_t setStopTimeUs(int64_t stopTimeUs);
 
+    // Gets the stop time offset in us. This is the time offset between latest buffer
+    // time and the stopTimeUs. If stop time is not set, INVALID_OPERATION will be returned.
+    // If return is OK, *stopTimeOffsetUs will contain the valid offset. Otherwise,
+    // *stopTimeOffsetUs will not be modified. Positive stopTimeOffsetUs means buffer time
+    // larger than stopTimeUs.
+    status_t getStopTimeOffsetUs(int64_t *stopTimeOffsetUs);
+
     // Sets the desired color aspects, e.g. to be used when producer does not specify a dataspace.
     status_t setColorAspects(int32_t aspectsPacked);
 
@@ -340,6 +347,8 @@
     // regardless of the metadata of those buffers
     bool areWeDiscardingAvailableBuffers_l();
 
+    int64_t mLastFrameTimestampUs;
+
     // Our BufferQueue interfaces. mProducer is passed to the producer through
     // getIGraphicBufferProducer, and mConsumer is used internally to retrieve
     // the buffers queued by the producer.
diff --git a/media/libstagefright/omx/OMXUtils.cpp b/media/libstagefright/omx/OMXUtils.cpp
index ee6d1d5..a66d565 100644
--- a/media/libstagefright/omx/OMXUtils.cpp
+++ b/media/libstagefright/omx/OMXUtils.cpp
@@ -24,6 +24,7 @@
 #include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/MediaDefs.h>
+#include <system/graphics-base.h>
 #include "OMXUtils.h"
 
 namespace android {
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
index a773ca2..fccb12b 100644
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -58,6 +58,7 @@
     { "OMX.google.vp8.encoder", "vpxenc", "video_encoder.vp8" },
     { "OMX.google.vp9.encoder", "vpxenc", "video_encoder.vp9" },
     { "OMX.google.raw.decoder", "rawdec", "audio_decoder.raw" },
+    { "OMX.google.flac.decoder", "flacdec", "audio_decoder.flac" },
     { "OMX.google.flac.encoder", "flacenc", "audio_encoder.flac" },
     { "OMX.google.gsm.decoder", "gsmdec", "audio_decoder.gsm" },
 };
diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
index 2aa88af..7ecfbbb 100644
--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
@@ -36,6 +36,8 @@
 
 #include <hardware/gralloc.h>
 
+#include <nativebase/nativebase.h>
+
 #include <OMX_IndexExt.h>
 
 namespace android {
diff --git a/media/libstagefright/omx/tests/Android.bp b/media/libstagefright/omx/tests/Android.bp
index 46428e3..8bcb99e 100644
--- a/media/libstagefright/omx/tests/Android.bp
+++ b/media/libstagefright/omx/tests/Android.bp
@@ -14,6 +14,7 @@
         "libcutils",
         "libhidlbase",
         "libhidlmemory",
+        "libnativewindow",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "android.hardware.media.omx@1.0",
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index fcc44d8..3266439 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -41,6 +41,7 @@
 #include <media/OMXBuffer.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <media/omx/1.0/WOmx.h>
+#include <system/window.h>
 
 #define DEFAULT_TIMEOUT         500000
 
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 5505aa4..c6c0245 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -33,6 +33,7 @@
 #include "ASessionDescription.h"
 
 #include <ctype.h>
+#include <cutils/properties.h>
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -135,7 +136,7 @@
           mCheckPending(false),
           mCheckGeneration(0),
           mCheckTimeoutGeneration(0),
-          mTryTCPInterleaving(false),
+          mTryTCPInterleaving(property_get_bool("rtp.transport.TCP", false)),
           mTryFakeRTCP(false),
           mReceivedFirstRTCPPacket(false),
           mReceivedFirstRTPPacket(false),
diff --git a/media/libstagefright/wifi-display/Android.bp b/media/libstagefright/wifi-display/Android.bp
index be23359..fb08c5b 100644
--- a/media/libstagefright/wifi-display/Android.bp
+++ b/media/libstagefright/wifi-display/Android.bp
@@ -29,6 +29,7 @@
         "libstagefright",
         "libstagefright_foundation",
         "libui",
+        "libgui",
         "libutils",
     ],
 
diff --git a/media/mtp/tests/Android.bp b/media/mtp/tests/Android.bp
index 356406d..fe7018b 100644
--- a/media/mtp/tests/Android.bp
+++ b/media/mtp/tests/Android.bp
@@ -16,6 +16,7 @@
 
 cc_test {
     name: "mtp_ffs_handle_test",
+    test_suites: ["device-tests"],
     srcs: ["MtpFfsHandle_test.cpp"],
     shared_libs: [
         "libbase",
diff --git a/media/mtp/tests/AndroidTest.xml b/media/mtp/tests/AndroidTest.xml
new file mode 100644
index 0000000..c1f4753
--- /dev/null
+++ b/media/mtp/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for mtp_ffs_handle_test">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="mtp_ffs_handle_test->/data/local/tmp/mtp_ffs_handle_test" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="mtp_ffs_handle_test" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 2c33fc2..c379c89 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -339,7 +339,6 @@
     AUDIO_HARDWARE_MODULE_ID_A2DP,
     AUDIO_HARDWARE_MODULE_ID_USB,
 };
-#define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0])))
 
 AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
         audio_module_handle_t module,
@@ -349,7 +348,7 @@
     // well known modules
     if (module == 0) {
         ALOGW("findSuitableHwDev_l() loading well know audio hw modules");
-        for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
+        for (size_t i = 0; i < arraysize(audio_interfaces); i++) {
             loadHwModule_l(audio_interfaces[i]);
         }
         // then try to find a module supporting the requested device.
@@ -519,7 +518,7 @@
 #ifdef TEE_SINK
         // dump the serially shared record tee sink
         if (mRecordTeeSource != 0) {
-            dumpTee(fd, mRecordTeeSource);
+            dumpTee(fd, mRecordTeeSource, AUDIO_IO_HANDLE_NONE, 'C');
         }
 #endif
 
@@ -3264,7 +3263,7 @@
 }
 
 #ifdef TEE_SINK
-void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id)
+void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id, char suffix)
 {
     NBAIO_Source *teeSource = source.get();
     if (teeSource != NULL) {
@@ -3326,7 +3325,8 @@
         struct tm tm;
         localtime_r(&tv.tv_sec, &tm);
         strftime(teeTime, sizeof(teeTime), "%Y%m%d%H%M%S", &tm);
-        snprintf(&teePath[teePathLen], sizeof(teePath) - teePathLen, "%s_%d.wav", teeTime, id);
+        snprintf(&teePath[teePathLen], sizeof(teePath) - teePathLen, "%s_%d_%c.wav", teeTime, id,
+                suffix);
         // if 2 dumpsys are done within 1 second, and rotation didn't work, then discard 2nd
         int teeFd = open(teePath, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, S_IRUSR | S_IWUSR);
         if (teeFd >= 0) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 75b4e4c..2e0bc66 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -25,6 +25,8 @@
 #include <sys/types.h>
 #include <limits.h>
 
+#include <android-base/macros.h>
+
 #include <cutils/compiler.h>
 #include <cutils/properties.h>
 
@@ -71,12 +73,11 @@
 #include <powermanager/IPowerManager.h>
 
 #include <media/nbaio/NBLog.h>
+#include <private/media/AudioEffectShared.h>
 #include <private/media/AudioTrackShared.h>
 
 namespace android {
 
-struct audio_track_cblk_t;
-struct effect_param_cblk_t;
 class AudioMixer;
 class AudioBuffer;
 class AudioResampler;
@@ -298,7 +299,8 @@
                             const sp<MmapStreamCallback>& callback,
                             sp<MmapStreamInterface>& interface);
 private:
-    static const size_t kLogMemorySize = 40 * 1024;
+    // FIXME The 400 is temporarily too high until a leak of writers in media.log is fixed.
+    static const size_t kLogMemorySize = 400 * 1024;
     sp<MemoryDealer>    mLogMemoryDealer;   // == 0 when NBLog is disabled
     // When a log writer is unregistered, it is done lazily so that media.log can continue to see it
     // for as long as possible.  The memory is only freed when it is needed for another log writer.
@@ -445,8 +447,8 @@
         sp<AudioFlinger>    audioFlinger() const { return mAudioFlinger; }
 
     private:
-                            Client(const Client&);
-                            Client& operator = (const Client&);
+        DISALLOW_COPY_AND_ASSIGN(Client);
+
         const sp<AudioFlinger> mAudioFlinger;
               sp<MemoryDealer> mMemoryDealer;
         const pid_t         mPid;
@@ -466,8 +468,7 @@
                 virtual     void        binderDied(const wp<IBinder>& who);
 
     private:
-                            NotificationClient(const NotificationClient&);
-                            NotificationClient& operator = (const NotificationClient&);
+        DISALLOW_COPY_AND_ASSIGN(NotificationClient);
 
         const sp<AudioFlinger>  mAudioFlinger;
         const pid_t             mPid;
@@ -824,7 +825,7 @@
 
 #ifdef TEE_SINK
     // tee sink, if enabled by property, allows dumpsys to write most recent audio to .wav file
-    static void dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id = 0);
+    static void dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id, char suffix);
 
     // whether tee sink is enabled by property
     static bool mTeeSinkInputEnabled;
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index b4029c7..f1a55f1 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -22,7 +22,6 @@
 #include "Configuration.h"
 #include <utils/Log.h>
 #include <audio_utils/primitives.h>
-#include <private/media/AudioEffectShared.h>
 #include <media/audiohal/EffectHalInterface.h>
 #include <media/audiohal/EffectsFactoryHalInterface.h>
 #include <system/audio_effects/effect_visualizer.h>
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 0755c52..e37529e 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -135,15 +135,14 @@
 
     void             dump(int fd, const Vector<String16>& args);
 
-protected:
+private:
     friend class AudioFlinger;      // for mHandles
     bool                mPinned;
 
     // Maximum time allocated to effect engines to complete the turn off sequence
     static const uint32_t MAX_DISABLE_TIME_MS = 10000;
 
-    EffectModule(const EffectModule&);
-    EffectModule& operator = (const EffectModule&);
+    DISALLOW_COPY_AND_ASSIGN(EffectModule);
 
     status_t start_l();
     status_t stop_l();
@@ -232,10 +231,9 @@
 
     void dumpToBuffer(char* buffer, size_t size);
 
-protected:
+private:
     friend class AudioFlinger;          // for mEffect, mHasControl, mEnabled
-    EffectHandle(const EffectHandle&);
-    EffectHandle& operator =(const EffectHandle&);
+    DISALLOW_COPY_AND_ASSIGN(EffectHandle);
 
     Mutex mLock;                        // protects IEffect method calls
     wp<EffectModule> mEffect;           // pointer to controlled EffectModule
@@ -366,10 +364,9 @@
 
     void dump(int fd, const Vector<String16>& args);
 
-protected:
+private:
     friend class AudioFlinger;  // for mThread, mEffects
-    EffectChain(const EffectChain&);
-    EffectChain& operator =(const EffectChain&);
+    DISALLOW_COPY_AND_ASSIGN(EffectChain);
 
     class SuspendedEffectDesc : public RefBase {
     public:
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
index 873a9ad..d063772 100644
--- a/services/audioflinger/FastCapture.cpp
+++ b/services/audioflinger/FastCapture.cpp
@@ -57,7 +57,7 @@
     return mSQ.poll();
 }
 
-void FastCapture::setLog(NBLog::Writer *logWriter __unused)
+void FastCapture::setNBLogWriter(NBLog::Writer *logWriter __unused)
 {
 }
 
diff --git a/services/audioflinger/FastCapture.h b/services/audioflinger/FastCapture.h
index e258a4d..c3817c0 100644
--- a/services/audioflinger/FastCapture.h
+++ b/services/audioflinger/FastCapture.h
@@ -39,7 +39,7 @@
 
     // callouts
     virtual const FastThreadState *poll();
-    virtual void setLog(NBLog::Writer *logWriter);
+    virtual void setNBLogWriter(NBLog::Writer *logWriter);
     virtual void onIdle();
     virtual void onExit();
     virtual bool isSubClassCommand(FastThreadState::Command command);
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 103e7f8..c4f1af3 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -41,6 +41,7 @@
 #include <audio_utils/format.h>
 #include <media/AudioMixer.h>
 #include "FastMixer.h"
+#include "TypedLogger.h"
 
 namespace android {
 
@@ -101,10 +102,12 @@
     return mSQ.poll();
 }
 
-void FastMixer::setLog(NBLog::Writer *logWriter)
+void FastMixer::setNBLogWriter(NBLog::Writer *logWriter)
 {
+    // FIXME If mMixer is set or changed prior to this, we don't inform correctly.
+    //       Should cache logWriter and re-apply it at the assignment to mMixer.
     if (mMixer != NULL) {
-        mMixer->setLog(logWriter);
+        mMixer->setNBLogWriter(logWriter);
     }
 }
 
@@ -135,6 +138,7 @@
 
 void FastMixer::onStateChange()
 {
+    LOG_HIST_FLUSH();
     const FastMixerState * const current = (const FastMixerState *) mCurrent;
     const FastMixerState * const previous = (const FastMixerState *) mPrevious;
     FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState;
@@ -188,6 +192,7 @@
             //       implementation; it would be better to have normal mixer allocate for us
             //       to avoid blocking here and to prevent possible priority inversion
             mMixer = new AudioMixer(frameCount, mSampleRate, FastMixerState::sMaxFastTracks);
+            // FIXME See the other FIXME at FastMixer::setNBLogWriter()
             const size_t mixerFrameSize = mSinkChannelCount
                     * audio_bytes_per_sample(mMixerBufferFormat);
             mMixerBufferSize = mixerFrameSize * frameCount;
@@ -330,6 +335,7 @@
 
 void FastMixer::onWork()
 {
+    LOG_HIST_TS();
     const FastMixerState * const current = (const FastMixerState *) mCurrent;
     FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState;
     const FastMixerState::Command command = mCommand;
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index bdfd8a0..930fa8d 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -46,7 +46,7 @@
 
     // callouts
     virtual const FastThreadState *poll();
-    virtual void setLog(NBLog::Writer *logWriter);
+    virtual void setNBLogWriter(NBLog::Writer *logWriter);
     virtual void onIdle();
     virtual void onExit();
     virtual bool isSubClassCommand(FastThreadState::Command command);
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index cf9fce3..85865b7 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -27,6 +27,7 @@
 #include <utils/Trace.h>
 #include "FastThread.h"
 #include "FastThreadDumpState.h"
+#include "TypedLogger.h"
 
 #define FAST_DEFAULT_NS    999999999L   // ~1 sec: default time to sleep
 #define FAST_HOT_IDLE_NS     1000000L   // 1 ms: time to sleep while hot idling
@@ -64,8 +65,8 @@
     /* mMeasuredWarmupTs({0, 0}), */
     mWarmupCycles(0),
     mWarmupConsecutiveInRangeCycles(0),
-    // mDummyLogWriter
-    mLogWriter(&mDummyLogWriter),
+    // mDummyNBLogWriter
+    mNBLogWriter(&mDummyNBLogWriter),
     mTimestampStatus(INVALID_OPERATION),
 
     mCommand(FastThreadState::INITIAL),
@@ -90,6 +91,9 @@
 
 bool FastThread::threadLoop()
 {
+    // LOGT now works even if tlNBLogWriter is nullptr, but we're considering changing that,
+    // so this initialization permits a future change to remove the check for nullptr.
+    tlNBLogWriter = &mDummyNBLogWriter;
     for (;;) {
 
         // either nanosleep, sched_yield, or busy wait
@@ -119,8 +123,9 @@
 
             // As soon as possible of learning of a new dump area, start using it
             mDumpState = next->mDumpState != NULL ? next->mDumpState : mDummyDumpState;
-            mLogWriter = next->mNBLogWriter != NULL ? next->mNBLogWriter : &mDummyLogWriter;
-            setLog(mLogWriter);
+            mNBLogWriter = next->mNBLogWriter != NULL ? next->mNBLogWriter : &mDummyNBLogWriter;
+            setNBLogWriter(mNBLogWriter);   // FastMixer informs its AudioMixer, FastCapture ignores
+            tlNBLogWriter = mNBLogWriter;
 
             // We want to always have a valid reference to the previous (non-idle) state.
             // However, the state queue only guarantees access to current and previous states.
@@ -218,7 +223,6 @@
         struct timespec newTs;
         int rc = clock_gettime(CLOCK_MONOTONIC, &newTs);
         if (rc == 0) {
-            //mLogWriter->logTimestamp(newTs);
             if (mOldTsValid) {
                 time_t sec = newTs.tv_sec - mOldTs.tv_sec;
                 long nsec = newTs.tv_nsec - mOldTs.tv_nsec;
diff --git a/services/audioflinger/FastThread.h b/services/audioflinger/FastThread.h
index 816b666..2a71414 100644
--- a/services/audioflinger/FastThread.h
+++ b/services/audioflinger/FastThread.h
@@ -41,7 +41,7 @@
     // callouts to subclass in same lexical order as they were in original FastMixer.cpp
     // FIXME need comments
     virtual const FastThreadState *poll() = 0;
-    virtual void setLog(NBLog::Writer *logWriter __unused) { }
+    virtual void setNBLogWriter(NBLog::Writer *logWriter __unused) { }
     virtual void onIdle() = 0;
     virtual void onExit() = 0;
     virtual bool isSubClassCommand(FastThreadState::Command command) = 0;
@@ -81,8 +81,8 @@
     struct timespec mMeasuredWarmupTs;  // how long did it take for warmup to complete
     uint32_t        mWarmupCycles;  // counter of number of loop cycles during warmup phase
     uint32_t        mWarmupConsecutiveInRangeCycles;    // number of consecutive cycles in range
-    NBLog::Writer   mDummyLogWriter;
-    NBLog::Writer*  mLogWriter;
+    NBLog::Writer   mDummyNBLogWriter;
+    NBLog::Writer*  mNBLogWriter;   // always non-nullptr: real NBLog::Writer* or &mDummyNBLogWriter
     status_t        mTimestampStatus;
 
     FastThreadState::Command mCommand;
diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h
index e4fe8ac..2a27dfd 100644
--- a/services/audioflinger/MmapTracks.h
+++ b/services/audioflinger/MmapTracks.h
@@ -41,11 +41,10 @@
      static void        appendDumpHeader(String8& result);
             void        dump(char* buffer, size_t size);
 
-protected:
+private:
     friend class MmapThread;
 
-                MmapTrack(const MmapTrack&);
-                MmapTrack& operator = (const MmapTrack&);
+    DISALLOW_COPY_AND_ASSIGN(MmapTrack);
 
     // AudioBufferProvider interface
     virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index f84ba08..3f1a0c0 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -94,8 +94,7 @@
     friend class DirectOutputThread;
     friend class OffloadThread;
 
-                        Track(const Track&);
-                        Track& operator = (const Track&);
+    DISALLOW_COPY_AND_ASSIGN(Track);
 
     // AudioBufferProvider interface
     virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 72ebc93..3f83ca8 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -65,8 +65,7 @@
 private:
     friend class AudioFlinger;  // for mState
 
-                        RecordTrack(const RecordTrack&);
-                        RecordTrack& operator = (const RecordTrack&);
+    DISALLOW_COPY_AND_ASSIGN(RecordTrack);
 
     // AudioBufferProvider interface
     virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a6857fe..df10d23 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -100,10 +100,6 @@
     return a < b ? a : b;
 }
 
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#endif
-
 namespace android {
 
 // retry counts for buffer fill timeout
@@ -2045,7 +2041,7 @@
             pid_t callingPid = IPCThreadState::self()->getCallingPid();
             // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
             // so ask activity manager to do this on our behalf
-            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true /*isForApp*/);
+            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true /*forApp*/);
         }
     }
 
@@ -2182,7 +2178,7 @@
         }
 
         char buffer[256];
-        track->dump(buffer, ARRAY_SIZE(buffer), false /* active */);
+        track->dump(buffer, arraysize(buffer), false /* active */);
         mLocalLog.log("addTrack_l    (%p) %s", track.get(), buffer + 4); // log for analysis
 
         status = NO_ERROR;
@@ -2212,7 +2208,7 @@
     track->triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE);
 
     char buffer[256];
-    track->dump(buffer, ARRAY_SIZE(buffer), false /* active */);
+    track->dump(buffer, arraysize(buffer), false /* active */);
     mLocalLog.log("removeTrack_l (%p) %s", track.get(), buffer + 4); // log for analysis
 
     mTracks.remove(track);
@@ -2930,7 +2926,7 @@
 
 bool AudioFlinger::PlaybackThread::threadLoop()
 {
-    logWriterTLS = mNBLogWriter.get();
+    tlNBLogWriter = mNBLogWriter.get();
 
     Vector< sp<Track> > tracksToRemove;
 
@@ -2957,9 +2953,13 @@
 
     acquireWakeLock();
 
-    // mNBLogWriter->log can only be called while thread mutex mLock is held.
+    // mNBLogWriter logging APIs can only be called by a single thread, typically the
+    // thread associated with this PlaybackThread.
+    // If you want to share the mNBLogWriter with other threads (for example, binder threads)
+    // then all such threads must agree to hold a common mutex before logging.
     // So if you need to log when mutex is unlocked, set logString to a non-NULL string,
     // and then that string will be logged at the next convenient opportunity.
+    // See reference to logString below.
     const char *logString = NULL;
 
     // Estimated time for next buffer to be written to hal. This is used only on
@@ -2967,9 +2967,7 @@
     nsecs_t timeLoopNextNs = 0;
 
     checkSilentMode_l();
-#if 0
-    int z = 0; // used in logFormat example
-#endif
+
     while (!exitPending())
     {
         // Log merge requests are performed during AudioFlinger binder transactions, but
@@ -2986,6 +2984,7 @@
 
             processConfigEvents_l();
 
+            // See comment at declaration of logString for why this is done under mLock
             if (logString != NULL) {
                 mNBLogWriter->logTimestamp();
                 mNBLogWriter->log(logString);
@@ -3412,7 +3411,7 @@
                 removeTrack_l(track);
             } else { // inactive but not terminated
                 char buffer[256];
-                track->dump(buffer, ARRAY_SIZE(buffer), false /* active */);
+                track->dump(buffer, arraysize(buffer), false /* active */);
                 mLocalLog.log("removeTracks_l(%p) %s", track.get(), buffer + 4);
             }
         }
@@ -3738,7 +3737,7 @@
         // start the fast mixer
         mFastMixer->run("FastMixer", PRIORITY_URGENT_AUDIO);
         pid_t tid = mFastMixer->getTid();
-        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false);
+        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false /*forApp*/);
         stream()->setHalThreadPriority(kPriorityFastMixer);
 
 #ifdef AUDIO_WATCHDOG
@@ -3747,7 +3746,7 @@
         mAudioWatchdog->setDump(&mAudioWatchdogDump);
         mAudioWatchdog->run("AudioWatchdog", PRIORITY_URGENT_AUDIO);
         tid = mAudioWatchdog->getTid();
-        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer);
+        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false /*forApp*/);
 #endif
 
     }
@@ -4775,7 +4774,7 @@
 
 #ifdef TEE_SINK
     // Write the tee output to a .wav file
-    dumpTee(fd, mTeeSource, mId);
+    dumpTee(fd, mTeeSource, mId, 'M');
 #endif
 
 }
@@ -5971,12 +5970,17 @@
     switch (kUseFastCapture) {
     case FastCapture_Never:
         initFastCapture = false;
+        ALOGV("%p kUseFastCapture = Never, initFastCapture = false", this);
         break;
     case FastCapture_Always:
         initFastCapture = true;
+        ALOGV("%p kUseFastCapture = Always, initFastCapture = true", this);
         break;
     case FastCapture_Static:
         initFastCapture = (mFrameCount * 1000) / mSampleRate < kMinNormalCaptureBufferSizeMs;
+        ALOGV("%p kUseFastCapture = Static, (%lld * 1000) / %u vs %u, initFastCapture = %d",
+                this, (long long)mFrameCount, mSampleRate, kMinNormalCaptureBufferSizeMs,
+                initFastCapture);
         break;
     // case FastCapture_Dynamic:
     }
@@ -5987,13 +5991,16 @@
         // quadruple-buffering of 20 ms each; this ensures we can sleep for 20ms in RecordThread
         size_t pipeFramesP2 = roundup(4 * FMS_20 * mSampleRate / 1000);
         size_t pipeSize = pipeFramesP2 * Format_frameSize(format);
-        void *pipeBuffer;
+        void *pipeBuffer = nullptr;
         const sp<MemoryDealer> roHeap(readOnlyHeap());
         sp<IMemory> pipeMemory;
         if ((roHeap == 0) ||
                 (pipeMemory = roHeap->allocate(pipeSize)) == 0 ||
-                (pipeBuffer = pipeMemory->pointer()) == NULL) {
-            ALOGE("not enough memory for pipe buffer size=%zu", pipeSize);
+                (pipeBuffer = pipeMemory->pointer()) == nullptr) {
+            ALOGE("not enough memory for pipe buffer size=%zu; "
+                    "roHeap=%p, pipeMemory=%p, pipeBuffer=%p; roHeapSize: %lld",
+                    pipeSize, roHeap.get(), pipeMemory.get(), pipeBuffer,
+                    (long long)kRecordThreadReadOnlyHeapSize);
             goto failed;
         }
         // pipe will be shared directly with fast clients, so clear to avoid leaking old information
@@ -6042,7 +6049,7 @@
         // start the fast capture
         mFastCapture->run("FastCapture", ANDROID_PRIORITY_URGENT_AUDIO);
         pid_t tid = mFastCapture->getTid();
-        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastCapture, false);
+        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastCapture, false /*forApp*/);
         stream()->setHalThreadPriority(kPriorityFastCapture);
 #ifdef AUDIO_WATCHDOG
         // FIXME
@@ -6635,19 +6642,19 @@
               audio_input_flags_t old = *flags;
               chain->checkInputFlagCompatibility(flags);
               if (old != *flags) {
-                  ALOGV("AUDIO_INPUT_FLAGS denied by effect old=%#x new=%#x",
-                          (int)old, (int)*flags);
+                  ALOGV("%p AUDIO_INPUT_FLAGS denied by effect old=%#x new=%#x",
+                          this, (int)old, (int)*flags);
               }
           }
           ALOGV_IF((*flags & AUDIO_INPUT_FLAG_FAST) != 0,
-                   "AUDIO_INPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu",
-                   frameCount, mFrameCount);
+                   "%p AUDIO_INPUT_FLAG_FAST accepted: frameCount=%zu mFrameCount=%zu",
+                   this, frameCount, mFrameCount);
       } else {
-        ALOGV("AUDIO_INPUT_FLAG_FAST denied: frameCount=%zu mFrameCount=%zu mPipeFramesP2=%zu "
-                "format=%#x isLinear=%d channelMask=%#x sampleRate=%u mSampleRate=%u "
+        ALOGV("%p AUDIO_INPUT_FLAG_FAST denied: frameCount=%zu mFrameCount=%zu mPipeFramesP2=%zu "
+                "format=%#x isLinear=%d mFormat=%#x channelMask=%#x sampleRate=%u mSampleRate=%u "
                 "hasFastCapture=%d tid=%d mFastTrackAvail=%d",
-                frameCount, mFrameCount, mPipeFramesP2,
-                format, audio_is_linear_pcm(format), channelMask, sampleRate, mSampleRate,
+                this, frameCount, mFrameCount, mPipeFramesP2,
+                format, audio_is_linear_pcm(format), mFormat, channelMask, sampleRate, mSampleRate,
                 hasFastCapture(), tid, mFastTrackAvail);
         *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_FAST);
       }
@@ -6714,7 +6721,7 @@
             pid_t callingPid = IPCThreadState::self()->getCallingPid();
             // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
             // so ask activity manager to do this on our behalf
-            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true);
+            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true /*forApp*/);
         }
     }
 
@@ -7244,6 +7251,10 @@
     result = mInput->stream->getBufferSize(&mBufferSize);
     LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving buffer size from HAL: %d", result);
     mFrameCount = mBufferSize / mFrameSize;
+    ALOGV("%p RecordThread params: mChannelCount=%u, mFormat=%#x, mFrameSize=%lld, "
+            "mBufferSize=%lld, mFrameCount=%lld",
+            this, mChannelCount, mFormat, (long long)mFrameSize, (long long)mBufferSize,
+            (long long)mFrameCount);
     // This is the formula for calculating the temporary buffer size.
     // With 7 HAL buffers, we can guarantee ability to down-sample the input by ratio of 6:1 to
     // 1 full output buffer, regardless of the alignment of the available input.
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 80b368e..9db19d6 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -229,8 +229,7 @@
         virtual     void        binderDied(const wp<IBinder>& who);
 
     private:
-                    PMDeathRecipient(const PMDeathRecipient&);
-                    PMDeathRecipient& operator = (const PMDeathRecipient&);
+        DISALLOW_COPY_AND_ASSIGN(PMDeathRecipient);
 
         wp<ThreadBase> mThread;
     };
@@ -901,7 +900,7 @@
 
     friend class AudioFlinger;      // for numerous
 
-    PlaybackThread& operator = (const PlaybackThread&);
+    DISALLOW_COPY_AND_ASSIGN(PlaybackThread);
 
     status_t    addTrack_l(const sp<Track>& track);
     bool        destroyTrack_l(const sp<Track>& track);
@@ -982,7 +981,7 @@
     sp<NBAIO_Source>        mTeeSource;
 #endif
     uint32_t                mScreenState;   // cached copy of gScreenState
-    static const size_t     kFastMixerLogSize = 4 * 1024;
+    static const size_t     kFastMixerLogSize = 8 * 1024;
     sp<NBLog::Writer>       mFastMixerNBLogWriter;
 
 
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index e0c09f7..cb540ca 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -92,8 +92,7 @@
 
 
 protected:
-                        TrackBase(const TrackBase&);
-                        TrackBase& operator = (const TrackBase&);
+    DISALLOW_COPY_AND_ASSIGN(TrackBase);
 
     // AudioBufferProvider interface
     virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 8fefb36..4c48e8b 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -234,7 +234,7 @@
 AudioFlinger::ThreadBase::TrackBase::~TrackBase()
 {
 #ifdef TEE_SINK
-    dumpTee(-1, mTeeSource, mId);
+    dumpTee(-1, mTeeSource, mId, 'T');
 #endif
     // delete the proxy before deleting the shared memory it refers to, to avoid dangling reference
     mServerProxy.clear();
diff --git a/services/audioflinger/TypedLogger.cpp b/services/audioflinger/TypedLogger.cpp
index e08f6f6..57c206b 100644
--- a/services/audioflinger/TypedLogger.cpp
+++ b/services/audioflinger/TypedLogger.cpp
@@ -23,5 +23,5 @@
 #include "TypedLogger.h"
 
 namespace android {
-thread_local NBLog::Writer *logWriterTLS;
+thread_local NBLog::Writer *tlNBLogWriter;
 }
diff --git a/services/audioflinger/TypedLogger.h b/services/audioflinger/TypedLogger.h
index 0b23c7c..2d84028 100644
--- a/services/audioflinger/TypedLogger.h
+++ b/services/audioflinger/TypedLogger.h
@@ -19,11 +19,84 @@
 #define ANDROID_TYPED_LOGGER_H
 
 #include <media/nbaio/NBLog.h>
-#define LOGT(fmt, ...) logWriterTLS->logFormat(fmt, ##__VA_ARGS__) // TODO: check null pointer
+#include <algorithm>
+
+/*
+Fowler-Noll-Vo (FNV-1a) hash function for the file name.
+Hashes at compile time. FNV-1a iterative function:
+
+hash = offset_basis
+for each byte to be hashed
+        hash = hash xor byte
+        hash = hash * FNV_prime
+return hash
+
+offset_basis and FNV_prime values depend on the size of the hash output
+Following values are defined by FNV and should not be changed arbitrarily
+*/
+
+template<typename T>
+constexpr T offset_basis();
+
+template<typename T>
+constexpr T FNV_prime();
+
+template<>
+constexpr uint32_t offset_basis<uint32_t>() {
+    return 2166136261u;
+}
+
+template<>
+constexpr uint32_t FNV_prime<uint32_t>() {
+    return 16777619u;
+}
+
+template<>
+constexpr uint64_t offset_basis<uint64_t>() {
+    return 14695981039346656037ull;
+}
+
+template<>
+constexpr uint64_t FNV_prime<uint64_t>() {
+    return 1099511628211ull;
+}
+
+template <typename T, size_t n>
+constexpr T fnv1a(const char (&file)[n], int i = n - 1) {
+    return i == -1 ? offset_basis<T>() : (fnv1a<T>(file, i - 1) ^ file[i]) * FNV_prime<T>();
+}
+
+template <size_t n>
+constexpr uint64_t hash(const char (&file)[n], uint32_t line) {
+    // Line numbers over or equal to 2^16 are clamped to 2^16 - 1. This way increases collisions
+    // compared to wrapping around, but is easy to identify because it doesn't produce aliasing.
+    // It's a very unlikely case anyways.
+    return ((fnv1a<uint64_t>(file) << 16) ^ ((fnv1a<uint64_t>(file) >> 32) & 0xFFFF0000)) |
+           std::min(line, 0xFFFFu);
+}
+
+// TODO Permit disabling of logging at compile-time.
+
+// TODO A non-nullptr dummy implementation that is a nop would be faster than checking for nullptr
+//      in the case when logging is enabled at compile-time and enabled at runtime, but it might be
+//      slower than nullptr check when logging is enabled at compile-time and disabled at runtime.
+
+// Write formatted entry to log
+#define LOGT(fmt, ...) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+                                x->logFormat((fmt), hash(__FILE__, __LINE__), ##__VA_ARGS__); } \
+                                while (0)
+
+// Write histogram timestamp entry
+#define LOG_HIST_TS() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+                                x->logHistTS(hash(__FILE__, __LINE__)); } while(0)
+
+// flush all histogram
+#define LOG_HIST_FLUSH() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+                                x->logHistFlush(hash(__FILE__, __LINE__)); } while(0)
 
 namespace android {
 extern "C" {
-extern thread_local NBLog::Writer *logWriterTLS;
+extern thread_local NBLog::Writer *tlNBLogWriter;
 }
 } // namespace android
 
diff --git a/services/audiopolicy/config/audio_policy_configuration_stub.xml b/services/audiopolicy/config/audio_policy_configuration_stub.xml
index a7747f8..26c381f 100644
--- a/services/audiopolicy/config/audio_policy_configuration_stub.xml
+++ b/services/audiopolicy/config/audio_policy_configuration_stub.xml
@@ -15,38 +15,9 @@
 -->
 
 <audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
-  <modules>
-        <module name="stub" halVersion="2.0">
-            <attachedDevices>
-                <item>Default Out</item>
-                <item>Default In</item>
-            </attachedDevices>
-            <defaultOutputDevice>Default Out</defaultOutputDevice>
-            <mixPorts>
-                <mixPort name="stub output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
-                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
-                </mixPort>
-
-                <mixPort name="stub input" role="sink">
-                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
-                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
-                </mixPort>
-            </mixPorts>
-            <devicePorts>
-                <devicePort tagName="Default Out" type="AUDIO_DEVICE_OUT_STUB" role="sink">
-                </devicePort>
-
-                <devicePort tagName="Default In" type="AUDIO_DEVICE_IN_STUB" role="source">
-                </devicePort>
-            </devicePorts>
-            <routes>
-                <route type="mix" sink="Default Out" sources="stub output"/>
-
-                <route type="mix" sink="stub input" sources="Default In"/>
-            </routes>
-
-        </module>
+    <modules>
+        <!-- Stub Audio HAL -->
+        <xi:include href="stub_audio_policy_configuration.xml"/>
 
         <!-- Remote Submix Audio HAL -->
         <xi:include href="r_submix_audio_policy_configuration.xml"/>
diff --git a/services/audiopolicy/config/stub_audio_policy_configuration.xml b/services/audiopolicy/config/stub_audio_policy_configuration.xml
new file mode 100644
index 0000000..17005d2
--- /dev/null
+++ b/services/audiopolicy/config/stub_audio_policy_configuration.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<module name="stub" halVersion="2.0">
+  <attachedDevices>
+    <item>Default Out</item>
+    <item>Default In</item>
+  </attachedDevices>
+  <defaultOutputDevice>Default Out</defaultOutputDevice>
+  <mixPorts>
+    <mixPort name="stub output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+      <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+               samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+    </mixPort>
+
+    <mixPort name="stub input" role="sink">
+      <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+               samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+    </mixPort>
+  </mixPorts>
+  <devicePorts>
+    <devicePort tagName="Default Out" type="AUDIO_DEVICE_OUT_STUB" role="sink">
+    </devicePort>
+
+    <devicePort tagName="Default In" type="AUDIO_DEVICE_IN_STUB" role="source">
+    </devicePort>
+  </devicePorts>
+  <routes>
+    <route type="mix" sink="Default Out" sources="stub output"/>
+
+    <route type="mix" sink="stub input" sources="Default In"/>
+  </routes>
+</module>
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 096ffd1..b6fff8c 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -552,6 +552,15 @@
                 AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED)) {
             device &= ~AUDIO_DEVICE_OUT_SPEAKER;
         }
+
+        // for STRATEGY_SONIFICATION:
+        // if SPEAKER was selected, and SPEAKER_SAFE is available, use SPEAKER_SAFE instead
+        if ((strategy == STRATEGY_SONIFICATION) &&
+                (device & AUDIO_DEVICE_OUT_SPEAKER) &&
+                (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+            device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+            device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+        }
         } break;
 
     default:
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index e8e531a..e0ce2d6 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -709,7 +709,8 @@
     // only retain flags that will drive the direct output profile selection
     // if explicitly requested
     static const uint32_t kRelevantFlags =
-            (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+            (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
+             AUDIO_OUTPUT_FLAG_VOIP_RX);
     flags =
         (audio_output_flags_t)((flags & kRelevantFlags) | AUDIO_OUTPUT_FLAG_DIRECT);
 
@@ -923,6 +924,12 @@
     }
     if (stream == AUDIO_STREAM_TTS) {
         flags = AUDIO_OUTPUT_FLAG_TTS;
+    } else if (stream == AUDIO_STREAM_VOICE_CALL &&
+               getPhoneState() == AUDIO_MODE_IN_COMMUNICATION &&
+               audio_is_linear_pcm(format)) {
+        flags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_VOIP_RX |
+                                       AUDIO_OUTPUT_FLAG_DIRECT);
+        ALOGV("Set VoIP and Direct output flags for PCM format");
     }
 
     sp<IOProfile> profile;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 4571db8..d6ed3ff 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2360,6 +2360,25 @@
     nsecs_t sensorTimestamp = request.sensorTimestamp;
     nsecs_t shutterTimestamp = request.shutterTimestamp;
 
+    bool skipResultMetadata = false;
+    if (request.requestStatus != OK) {
+        switch (request.requestStatus) {
+            case CAMERA3_MSG_ERROR_DEVICE:
+            case CAMERA3_MSG_ERROR_REQUEST:
+            case CAMERA3_MSG_ERROR_RESULT:
+                skipResultMetadata = true;
+                break;
+            case CAMERA3_MSG_ERROR_BUFFER:
+                //Result metadata should return in this case.
+                skipResultMetadata = false;
+                break;
+            default:
+                SET_ERR("Unknown error message: %d", request.requestStatus);
+                skipResultMetadata = false;
+                break;
+        }
+    }
+
     // Check if it's okay to remove the request from InFlightMap:
     // In the case of a successful request:
     //      all input and output buffers, all result metadata, shutter callback
@@ -2367,7 +2386,7 @@
     // In the case of a unsuccessful request:
     //      all input and output buffers arrived.
     if (request.numBuffersLeft == 0 &&
-            (request.requestStatus != OK ||
+            (skipResultMetadata ||
             (request.haveResultMetadata && shutterTimestamp != 0))) {
         ATRACE_ASYNC_END("frame capture", frameNumber);
 
diff --git a/services/mediaanalytics/MetricsSummarizer.cpp b/services/mediaanalytics/MetricsSummarizer.cpp
index 6d5787e..3477f1f 100644
--- a/services/mediaanalytics/MetricsSummarizer.cpp
+++ b/services/mediaanalytics/MetricsSummarizer.cpp
@@ -153,11 +153,11 @@
                 ALOGE("unable to save MediaMetrics record");
             }
             sortProps(item);
-            item->setInt32("aggregated",1);
+            item->setInt32("count",1);
             mSummaries->push_back(item);
     } else {
             ALOGV("increment existing record");
-            (*it)->addInt32("aggregated",1);
+            (*it)->addInt32("count",1);
             mergeRecord(*(*it), *item);
     }
 }
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index aaf1018..a5512e1 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -26,7 +26,7 @@
 
 namespace android {
 
-// static const char kDeadlockedString[] = "MediaLogService may be deadlocked\n";
+ static const char kDeadlockedString[] = "MediaLogService may be deadlocked\n";
 MediaLogService::MediaLogService() :
     BnMediaLogService(),
     mMergerShared((NBLog::Shared*) malloc(NBLog::Timeline::sharedSize(kMergeBufferSize))),
@@ -99,35 +99,38 @@
         return NO_ERROR;
     }
 
-#if 0
-    Vector<NBLog::NamedReader> namedReaders;
-    {
-        bool locked = dumpTryLock(mLock);
+    if (args.size() > 0) {
+        const String8 arg0(args[0]);
+        if (!strcmp(arg0.string(), "-r")) {
+            // needed because mNamedReaders is protected by mLock
+            bool locked = dumpTryLock(mLock);
 
-        // failed to lock - MediaLogService is probably deadlocked
-        if (!locked) {
-            String8 result(kDeadlockedString);
-            if (fd >= 0) {
-                write(fd, result.string(), result.size());
-            } else {
-                ALOGW("%s:", result.string());
+            // failed to lock - MediaLogService is probably deadlocked
+            if (!locked) {
+                String8 result(kDeadlockedString);
+                if (fd >= 0) {
+                    write(fd, result.string(), result.size());
+                } else {
+                    ALOGW("%s:", result.string());
+                }
+                // TODO should we instead proceed to mMergeReader.dump? does it need lock?
+                return NO_ERROR;
             }
-            return NO_ERROR;
-        }
-            // namedReaders = mNamedReaders;
-            // for (size_t i = 0; i < namedReaders.size(); i++) {
-            //     const NBLog::NamedReader& namedReader = namedReaders[i];
-            //     if (fd >= 0) {
-            //         dprintf(fd, "\n%s:\n", namedReader.name());
-            //     } else {
-            //         ALOGI("%s:", namedReader.name());
-            //     }
-            //     namedReader.reader()->dump(fd, 0 /*indent*/);
-            // }
 
-        mLock.unlock();
+            for (const auto& namedReader : mNamedReaders) {
+                if (fd >= 0) {
+                    dprintf(fd, "\n%s:\n", namedReader.name());
+                } else {
+                    ALOGI("%s:", namedReader.name());
+                }
+                // TODO This code is for testing, remove it when done
+                // namedReader.reader()->dump(fd, 0 /*indent*/);
+            }
+
+            mLock.unlock();
+        }
     }
-#endif
+
     // FIXME request merge to make sure log is up to date
     mMergeReader.dump(fd);
     return NO_ERROR;
diff --git a/services/medialog/MediaLogService.h b/services/medialog/MediaLogService.h
index c6b99f1..39d9cc0 100644
--- a/services/medialog/MediaLogService.h
+++ b/services/medialog/MediaLogService.h
@@ -49,12 +49,15 @@
     // Internal dump
     static const int kDumpLockRetries = 50;
     static const int kDumpLockSleepUs = 20000;
-    static const size_t kMergeBufferSize = 16 * 1024; // TODO determine good value for this
+    // Size of merge buffer, in bytes
+    static const size_t kMergeBufferSize = 64 * 1024; // TODO determine good value for this
     static bool dumpTryLock(Mutex& mutex);
 
     Mutex               mLock;
 
-    Vector<NBLog::NamedReader> mNamedReaders;
+    Vector<NBLog::NamedReader> mNamedReaders;   // protected by mLock
+
+    // FIXME Need comments on all of these, especially about locking
     NBLog::Shared *mMergerShared;
     NBLog::Merger mMerger;
     NBLog::MergeReader mMergeReader;