Merge "Added number of encoded frames and duration to the MPEG4Writer::Track::dump"
diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp
index 059a8a5..872512a 100644
--- a/camera/CameraParameters.cpp
+++ b/camera/CameraParameters.cpp
@@ -155,6 +155,7 @@
 const char CameraParameters::PIXEL_FORMAT_RGBA8888[] = "rgba8888";
 const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg";
 const char CameraParameters::PIXEL_FORMAT_BAYER_RGGB[] = "bayer-rggb";
+const char CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE[] = "android-opaque";
 
 // Values for focus mode settings.
 const char CameraParameters::FOCUS_MODE_AUTO[] = "auto";
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 36248a0..4d5aa36 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -606,6 +606,8 @@
     // Raw bayer format used for images, which is 10 bit precision samples
     // stored in 16 bit words. The filter pattern is RGGB.
     static const char PIXEL_FORMAT_BAYER_RGGB[];
+    // Pixel format is not known to the framework
+    static const char PIXEL_FORMAT_ANDROID_OPAQUE[];
 
     // Values for focus mode settings.
     // Auto-focus mode. Applications should call
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 7e66ac9..156c592 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -84,8 +84,8 @@
      *          more bytes than indicated by 'size' field and update 'size' if less bytes are
      *          read.
      *          - EVENT_OVERRUN: unused.
-     *          - EVENT_MARKER: pointer to an uin32_t containing the marker position in frames.
-     *          - EVENT_NEW_POS: pointer to an uin32_t containing the new position in frames.
+     *          - EVENT_MARKER: pointer to const uint32_t containing the marker position in frames.
+     *          - EVENT_NEW_POS: pointer to const uint32_t containing the new position in frames.
      */
 
     typedef void (*callback_t)(int event, void* user, void *info);
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 1fad383..f7cebc5 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -99,6 +99,8 @@
     // The player was started because it was used as the next player for another
     // player, which just completed playback
     MEDIA_INFO_STARTED_AS_NEXT = 2,
+    // The player just pushed the very first video frame for rendering
+    MEDIA_INFO_RENDERING_START = 3,
     // 7xx
     // The video is too complex for the decoder: it can't decode frames fast
     // enough. Possibly only the audio plays fine at this stage.
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 9d5813b..5060525 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -355,7 +355,6 @@
 
 uint32_t AudioRecord::getSampleRate() const
 {
-    AutoMutex lock(mLock);
     return mCblk->sampleRate;
 }
 
@@ -363,6 +362,7 @@
 {
     if (mCbf == NULL) return INVALID_OPERATION;
 
+    AutoMutex lock(mLock);
     mMarkerPosition = marker;
     mMarkerReached = false;
 
@@ -373,6 +373,7 @@
 {
     if (marker == NULL) return BAD_VALUE;
 
+    AutoMutex lock(mLock);
     *marker = mMarkerPosition;
 
     return NO_ERROR;
@@ -384,6 +385,8 @@
 
     uint32_t curPosition;
     getPosition(&curPosition);
+
+    AutoMutex lock(mLock);
     mNewPosition = curPosition + updatePeriod;
     mUpdatePeriod = updatePeriod;
 
@@ -394,6 +397,7 @@
 {
     if (updatePeriod == NULL) return BAD_VALUE;
 
+    AutoMutex lock(mLock);
     *updatePeriod = mUpdatePeriod;
 
     return NO_ERROR;
@@ -434,6 +438,7 @@
     pid_t tid = -1;
     // FIXME see similar logic at AudioTrack
 
+    int originalSessionId = mSessionId;
     sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), input,
                                                        sampleRate, format,
                                                        channelMask,
@@ -442,6 +447,8 @@
                                                        tid,
                                                        &mSessionId,
                                                        &status);
+    ALOGE_IF(originalSessionId != 0 && mSessionId != originalSessionId,
+            "session ID changed from %d to %d", originalSessionId, mSessionId);
 
     if (record == 0) {
         ALOGE("AudioFlinger could not create record track, status: %d", status);
@@ -587,6 +594,7 @@
 
 int AudioRecord::getSessionId() const
 {
+    // no lock needed because session ID doesn't change after first set()
     return mSessionId;
 }
 
@@ -658,22 +666,31 @@
     sp<IMemory> iMem = mCblkMemory;
     audio_track_cblk_t* cblk = mCblk;
     bool active = mActive;
+    uint32_t markerPosition = mMarkerPosition;
+    uint32_t newPosition = mNewPosition;
+    uint32_t user = cblk->user;
+    // determine whether a marker callback will be needed, while locked
+    bool needMarker = !mMarkerReached && (mMarkerPosition > 0) && (user >= mMarkerPosition);
+    if (needMarker) {
+        mMarkerReached = true;
+    }
+    // determine the number of new position callback(s) that will be needed, while locked
+    uint32_t updatePeriod = mUpdatePeriod;
+    uint32_t needNewPos = updatePeriod > 0 && user >= newPosition ?
+            ((user - newPosition) / updatePeriod) + 1 : 0;
+    mNewPosition = newPosition + updatePeriod * needNewPos;
     mLock.unlock();
 
-    // Manage marker callback
-    if (!mMarkerReached && (mMarkerPosition > 0)) {
-        if (cblk->user >= mMarkerPosition) {
-            mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
-            mMarkerReached = true;
-        }
+    // perform marker callback, while unlocked
+    if (needMarker) {
+        mCbf(EVENT_MARKER, mUserData, &markerPosition);
     }
 
-    // Manage new position callback
-    if (mUpdatePeriod > 0) {
-        while (cblk->user >= mNewPosition) {
-            mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
-            mNewPosition += mUpdatePeriod;
-        }
+    // perform new position callback(s), while unlocked
+    for (; needNewPos > 0; --needNewPos) {
+        uint32_t temp = newPosition;
+        mCbf(EVENT_NEW_POS, mUserData, &temp);
+        newPosition += updatePeriod;
     }
 
     do {
@@ -721,7 +738,7 @@
         // otherwise we would have exited when obtainBuffer returned STOPPED earlier.
         ALOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
         if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) {
-            mCbf(EVENT_OVERRUN, mUserData, 0);
+            mCbf(EVENT_OVERRUN, mUserData, NULL);
         }
     }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 86e122f..8f45491 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -500,6 +500,8 @@
                 CHECK(msg->findInt32("audio", &audio));
 
                 ALOGV("renderer %s flush completed.", audio ? "audio" : "video");
+            } else if (what == Renderer::kWhatVideoRenderingStart) {
+                notifyListener(MEDIA_INFO, MEDIA_INFO_RENDERING_START, 0);
             }
             break;
         }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 1f13955..8a75f83 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -47,6 +47,7 @@
       mHasVideo(false),
       mSyncQueues(false),
       mPaused(false),
+      mVideoRenderingStarted(false),
       mLastPositionUpdateUs(-1ll),
       mVideoLateByUs(0ll) {
 }
@@ -387,9 +388,20 @@
     mVideoQueue.erase(mVideoQueue.begin());
     entry = NULL;
 
+    if (!mVideoRenderingStarted) {
+        mVideoRenderingStarted = true;
+        notifyVideoRenderingStart();
+    }
+
     notifyPosition();
 }
 
+void NuPlayer::Renderer::notifyVideoRenderingStart() {
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatVideoRenderingStart);
+    notify->post();
+}
+
 void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult) {
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatEOS);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 268628b..e4368c7 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -45,9 +45,10 @@
     void resume();
 
     enum {
-        kWhatEOS                = 'eos ',
-        kWhatFlushComplete      = 'fluC',
-        kWhatPosition           = 'posi',
+        kWhatEOS                 = 'eos ',
+        kWhatFlushComplete       = 'fluC',
+        kWhatPosition            = 'posi',
+        kWhatVideoRenderingStart = 'vdrd',
     };
 
 protected:
@@ -99,6 +100,7 @@
     bool mSyncQueues;
 
     bool mPaused;
+    bool mVideoRenderingStarted;
 
     int64_t mLastPositionUpdateUs;
     int64_t mVideoLateByUs;
@@ -120,6 +122,7 @@
     void notifyFlushComplete(bool audio);
     void notifyPosition();
     void notifyVideoLateBy(int64_t lateByUs);
+    void notifyVideoRenderingStart();
 
     void flushQueue(List<QueueEntry> *queue);
     bool dropBufferWhileFlushing(bool audio, const sp<AMessage> &msg);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 2c68075..664d5dd 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -183,6 +183,7 @@
     : mQueueStarted(false),
       mUIDValid(false),
       mTimeSource(NULL),
+      mVideoRenderingStarted(false),
       mVideoRendererIsPreview(false),
       mAudioPlayer(NULL),
       mDisplayWidth(0),
@@ -468,6 +469,7 @@
 }
 
 void AwesomePlayer::reset_l() {
+    mVideoRenderingStarted = false;
     mActiveAudioTrackIndex = -1;
     mDisplayWidth = 0;
     mDisplayHeight = 0;
@@ -710,7 +712,6 @@
                              kHighWaterMarkBytes);
                         modifyFlags(CACHE_UNDERRUN, CLEAR);
                         play_l();
-                        notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
                     } else if (mFlags & PREPARING) {
                         ALOGV("cache has filled up (> %d), prepare is done",
                              kHighWaterMarkBytes);
@@ -770,7 +771,6 @@
                           cachedDurationUs / 1E6);
                     play_l();
                 }
-                notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
             } else if (mFlags & PREPARING) {
                 ALOGV("cache has filled up (%.2f secs), prepare is done",
                      cachedDurationUs / 1E6);
@@ -1807,6 +1807,11 @@
     if (mVideoRenderer != NULL) {
         mSinceLastDropped++;
         mVideoRenderer->render(mVideoBuffer);
+        if (!mVideoRenderingStarted) {
+            mVideoRenderingStarted = true;
+            notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START);
+        }
+
     }
 
     mVideoBuffer->release();
@@ -2626,6 +2631,9 @@
             mFlags |= value;
             break;
         case CLEAR:
+            if ((value & CACHE_UNDERRUN) && (mFlags & CACHE_UNDERRUN)) {
+                notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
+            }
             mFlags &= ~value;
             break;
         case ASSIGN:
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 68380a8..1422687 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -166,6 +166,7 @@
     sp<MediaSource> mVideoTrack;
     sp<MediaSource> mVideoSource;
     sp<AwesomeRenderer> mVideoRenderer;
+    bool mVideoRenderingStarted;
     bool mVideoRendererIsPreview;
 
     ssize_t mActiveAudioTrackIndex;
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.cpp b/media/libstagefright/timedtext/TimedTextSRTSource.cpp
index 1f5d037..eac23ba 100644
--- a/media/libstagefright/timedtext/TimedTextSRTSource.cpp
+++ b/media/libstagefright/timedtext/TimedTextSRTSource.cpp
@@ -79,6 +79,10 @@
     return OK;
 }
 
+sp<MetaData> TimedTextSRTSource::getFormat() {
+    return mMetaData;
+}
+
 status_t TimedTextSRTSource::scanFile() {
     off64_t offset = 0;
     int64_t startTimeUs;
@@ -155,18 +159,16 @@
     while (needMoreData) {
         if ((err = readNextLine(offset, &data)) != OK) {
             if (err == ERROR_END_OF_STREAM) {
-                needMoreData = false;
+                break;
             } else {
                 return err;
             }
         }
 
-        if (needMoreData) {
-            data.trim();
-            if (data.empty()) {
-                // it's an empty line used to separate two subtitles
-                needMoreData = false;
-            }
+        data.trim();
+        if (data.empty()) {
+            // it's an empty line used to separate two subtitles
+            needMoreData = false;
         }
     }
     info->textLen = *offset - info->offset;
@@ -221,35 +223,24 @@
     if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
         int64_t lastEndTimeUs =
                 mTextVector.valueAt(mTextVector.size() - 1).endTimeUs;
-        int64_t firstStartTimeUs = mTextVector.keyAt(0);
-        if (seekTimeUs < 0 || seekTimeUs > lastEndTimeUs) {
+        if (seekTimeUs < 0) {
             return ERROR_OUT_OF_RANGE;
-        } else if (seekTimeUs < firstStartTimeUs) {
-            mIndex = 0;
+        } else if (seekTimeUs >= lastEndTimeUs) {
+            return ERROR_END_OF_STREAM;
         } else {
             // binary search
             size_t low = 0;
             size_t high = mTextVector.size() - 1;
             size_t mid = 0;
-            int64_t currTimeUs;
 
             while (low <= high) {
                 mid = low + (high - low)/2;
-                currTimeUs = mTextVector.keyAt(mid);
-                const int64_t diffTime = currTimeUs - seekTimeUs;
-
-                if (diffTime == 0) {
+                int diff = compareExtendedRangeAndTime(mid, seekTimeUs);
+                if (diff == 0) {
                     break;
-                } else if (diffTime < 0) {
+                } else if (diff < 0) {
                     low = mid + 1;
                 } else {
-                    if ((high == mid + 1)
-                        && (seekTimeUs < mTextVector.keyAt(high))) {
-                        break;
-                    }
-                    if (mid < 1) {
-                        break;
-                    }
                     high = mid - 1;
                 }
             }
@@ -260,6 +251,7 @@
     if (mIndex >= mTextVector.size()) {
         return ERROR_END_OF_STREAM;
     }
+
     const TextInfo &info = mTextVector.valueAt(mIndex);
     *startTimeUs = mTextVector.keyAt(mIndex);
     *endTimeUs = info.endTimeUs;
@@ -289,8 +281,18 @@
     return OK;
 }
 
-sp<MetaData> TimedTextSRTSource::getFormat() {
-    return mMetaData;
+int TimedTextSRTSource::compareExtendedRangeAndTime(size_t index, int64_t timeUs) {
+    CHECK_LT(index, mTextVector.size());
+    int64_t endTimeUs = mTextVector.valueAt(index).endTimeUs;
+    int64_t startTimeUs = (index > 0) ?
+            mTextVector.valueAt(index - 1).endTimeUs : 0;
+    if (timeUs >= startTimeUs && timeUs < endTimeUs) {
+        return 0;
+    } else if (endTimeUs <= timeUs) {
+        return -1;
+    } else {
+        return 1;
+    }
 }
 
 }  // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.h b/media/libstagefright/timedtext/TimedTextSRTSource.h
index 9eeab39..598c200 100644
--- a/media/libstagefright/timedtext/TimedTextSRTSource.h
+++ b/media/libstagefright/timedtext/TimedTextSRTSource.h
@@ -70,6 +70,25 @@
     status_t extractAndAppendLocalDescriptions(
             int64_t timeUs, const AString &text, Parcel *parcel);
 
+    // Compares the time range of the subtitle at index to the given timeUs.
+    // The time range of the subtitle to match with given timeUs is extended to
+    // [endTimeUs of the previous subtitle, endTimeUs of current subtitle).
+    //
+    // This compare function is used to find a next subtitle when read() is
+    // called with seek options. Note that timeUs within gap ranges, such as
+    // [200, 300) in the below example, will be matched to the closest future
+    // subtitle, [300, 400).
+    //
+    // For instance, assuming there are 3 subtitles in mTextVector,
+    // 0: [100, 200)      ----> [0, 200)
+    // 1: [300, 400)      ----> [200, 400)
+    // 2: [500, 600)      ----> [400, 600)
+    // If the 'index' parameter contains 1, this function
+    // returns 0, if timeUs is in [200, 400)
+    // returns -1, if timeUs >= 400,
+    // returns 1, if timeUs < 200.
+    int compareExtendedRangeAndTime(size_t index, int64_t timeUs);
+
     DISALLOW_EVIL_CONSTRUCTORS(TimedTextSRTSource);
 };
 
diff --git a/media/libstagefright/timedtext/test/Android.mk b/media/libstagefright/timedtext/test/Android.mk
new file mode 100644
index 0000000..a5e7ba2
--- /dev/null
+++ b/media/libstagefright/timedtext/test/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH:= $(call my-dir)
+
+# ================================================================
+# Unit tests for libstagefright_timedtext
+# See also /development/testrunner/test_defs.xml
+# ================================================================
+
+# ================================================================
+# A test for TimedTextSRTSource
+# ================================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := TimedTextSRTSource_test
+
+LOCAL_MODULE_TAGS := eng tests
+
+LOCAL_SRC_FILES := TimedTextSRTSource_test.cpp
+
+LOCAL_C_INCLUDES := \
+    $(TOP)/external/expat/lib \
+    $(TOP)/frameworks/base/media/libstagefright/timedtext
+
+LOCAL_SHARED_LIBRARIES := \
+    libexpat \
+    libstagefright
+
+include $(BUILD_NATIVE_TEST)
diff --git a/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp b/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp
new file mode 100644
index 0000000..40e93c7
--- /dev/null
+++ b/media/libstagefright/timedtext/test/TimedTextSRTSource_test.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TimedTextSRTSource_test"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include <binder/Parcel.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/misc.h>
+
+#include <TimedTextSource.h>
+#include <TimedTextSRTSource.h>
+
+namespace android {
+namespace test {
+
+static const int kSecToUsec = 1000000;
+static const int kSecToMsec = 1000;
+static const int kMsecToUsec = 1000;
+
+/* SRT format (http://en.wikipedia.org/wiki/SubRip)
+ *   Subtitle number
+ *   Start time --> End time
+ *   Text of subtitle (one or more lines)
+ *   Blank lines
+ */
+static const char *kSRTString =
+    "1\n00:00:1,000 --> 00:00:1,500\n1\n\n"
+    "2\n00:00:2,000 --> 00:00:2,500\n2\n\n"
+    "3\n00:00:3,000 --> 00:00:3,500\n3\n\n"
+    "4\n00:00:4,000 --> 00:00:4,500\n4\n\n"
+    "5\n00:00:5,000 --> 00:00:5,500\n5\n\n"
+    // edge case : previos end time = next start time
+    "6\n00:00:5,500 --> 00:00:5,800\n6\n\n"
+    "7\n00:00:5,800 --> 00:00:6,000\n7\n\n"
+    "8\n00:00:6,000 --> 00:00:7,000\n8\n\n";
+
+class SRTDataSourceStub : public DataSource {
+public:
+    SRTDataSourceStub(const char *data, size_t size) :
+        mData(data), mSize(size) {}
+    virtual ~SRTDataSourceStub() {}
+
+    virtual status_t initCheck() const {
+        return OK;
+    }
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
+        if (offset >= mSize) return 0;
+
+        ssize_t avail = mSize - offset;
+        if (avail > size) {
+            avail = size;
+        }
+        memcpy(data, mData + offset, avail);
+        return avail;
+    }
+
+private:
+    const char *mData;
+    size_t mSize;
+};
+
+class TimedTextSRTSourceTest : public testing::Test {
+protected:
+    void SetUp() {
+        sp<DataSource> stub= new SRTDataSourceStub(
+                kSRTString,
+                strlen(kSRTString));
+        mSource = new TimedTextSRTSource(stub);
+        mSource->start();
+    }
+
+    void CheckStartTimeMs(const Parcel& parcel, int32_t timeMs) {
+        int32_t intval;
+        parcel.setDataPosition(8);
+        parcel.readInt32(&intval);
+        EXPECT_EQ(timeMs, intval);
+    }
+
+    void CheckDataEquals(const Parcel& parcel, const char* content) {
+        int32_t intval;
+        parcel.setDataPosition(16);
+        parcel.readInt32(&intval);
+        parcel.setDataPosition(24);
+        const char* data = (const char*) parcel.readInplace(intval);
+
+        int32_t content_len = strlen(content);
+        EXPECT_EQ(content_len, intval);
+        EXPECT_TRUE(strncmp(data, content, content_len) == 0);
+    }
+
+    sp<TimedTextSource> mSource;
+    int64_t startTimeUs;
+    int64_t endTimeUs;
+    Parcel parcel;
+    AString subtitle;
+    status_t err;
+};
+
+TEST_F(TimedTextSRTSourceTest, readAll) {
+    for (int i = 1; i <= 5; i++) {
+        err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
+        EXPECT_EQ(OK, err);
+        CheckStartTimeMs(parcel, i * kSecToMsec);
+        subtitle = StringPrintf("%d\n\n", i);
+        CheckDataEquals(parcel, subtitle.c_str());
+    }
+    // read edge cases
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
+    EXPECT_EQ(OK, err);
+    CheckStartTimeMs(parcel, 5500);
+    subtitle = StringPrintf("6\n\n");
+    CheckDataEquals(parcel, subtitle.c_str());
+
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
+    EXPECT_EQ(OK, err);
+    CheckStartTimeMs(parcel, 5800);
+    subtitle = StringPrintf("7\n\n");
+    CheckDataEquals(parcel, subtitle.c_str());
+
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
+    EXPECT_EQ(OK, err);
+    CheckStartTimeMs(parcel, 6000);
+    subtitle = StringPrintf("8\n\n");
+    CheckDataEquals(parcel, subtitle.c_str());
+
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
+    EXPECT_EQ(ERROR_END_OF_STREAM, err);
+}
+
+TEST_F(TimedTextSRTSourceTest, seekTimeIsEarlierThanFirst) {
+    MediaSource::ReadOptions options;
+    options.setSeekTo(500, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+    EXPECT_EQ(OK, err);
+    EXPECT_EQ(1 * kSecToUsec, startTimeUs);
+    CheckStartTimeMs(parcel, 1 * kSecToMsec);
+}
+
+TEST_F(TimedTextSRTSourceTest, seekTimeIsLaterThanLast) {
+    MediaSource::ReadOptions options;
+    options.setSeekTo(7 * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+    EXPECT_EQ(ERROR_END_OF_STREAM, err);
+
+    options.setSeekTo(8 * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+    EXPECT_EQ(ERROR_END_OF_STREAM, err);
+}
+
+TEST_F(TimedTextSRTSourceTest, seekTimeIsMatched) {
+    for (int i = 1; i <= 5; i++) {
+        MediaSource::ReadOptions options;
+        options.setSeekTo(i * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+        err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+        EXPECT_EQ(OK, err);
+        EXPECT_EQ(i * kSecToUsec, startTimeUs);
+
+        options.setSeekTo(i * kSecToUsec + 100, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+        err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+        EXPECT_EQ(OK, err);
+        EXPECT_EQ(i * kSecToUsec, startTimeUs);
+    }
+}
+
+TEST_F(TimedTextSRTSourceTest, seekTimeInBetweenTwo) {
+    for (int i = 1; i <= 4; i++) {
+        MediaSource::ReadOptions options;
+        options.setSeekTo(i * kSecToUsec + 500000, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+        err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+        EXPECT_EQ(OK, err);
+        EXPECT_EQ((i + 1) * kSecToUsec, startTimeUs);
+
+        options.setSeekTo(i * kSecToUsec + 600000, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+        err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+        EXPECT_EQ(OK, err);
+        EXPECT_EQ((i + 1) * kSecToUsec, startTimeUs);
+    }
+}
+
+TEST_F(TimedTextSRTSourceTest, checkEdgeCase) {
+    MediaSource::ReadOptions options;
+    options.setSeekTo(5500 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+    EXPECT_EQ(OK, err);
+    EXPECT_EQ(5500 * kMsecToUsec, startTimeUs);
+    subtitle = StringPrintf("6\n\n");
+    CheckDataEquals(parcel, subtitle.c_str());
+
+    options.setSeekTo(5800 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+    EXPECT_EQ(OK, err);
+    EXPECT_EQ(5800 * kMsecToUsec, startTimeUs);
+    subtitle = StringPrintf("7\n\n");
+    CheckDataEquals(parcel, subtitle.c_str());
+
+    options.setSeekTo(6000 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+    err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
+    EXPECT_EQ(OK, err);
+    EXPECT_EQ(6000 * kMsecToUsec, startTimeUs);
+    subtitle = StringPrintf("8\n\n");
+    CheckDataEquals(parcel, subtitle.c_str());
+}
+
+}  // namespace test
+}  // namespace android
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b2aa388..424d8bc 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -299,7 +299,7 @@
     return NULL;
 }
 
-status_t AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -322,11 +322,10 @@
         result.append(buffer);
     }
     write(fd, result.string(), result.size());
-    return NO_ERROR;
 }
 
 
-status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -339,10 +338,9 @@
                             (uint32_t)(mStandbyTimeInNsecs / 1000000));
     result.append(buffer);
     write(fd, result.string(), result.size());
-    return NO_ERROR;
 }
 
-status_t AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -353,7 +351,6 @@
             IPCThreadState::self()->getCallingUid());
     result.append(buffer);
     write(fd, result.string(), result.size());
-    return NO_ERROR;
 }
 
 static bool tryLock(Mutex& mutex)
@@ -1216,7 +1213,7 @@
     mLock.unlock();
 }
 
-status_t AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args)
+void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -1273,10 +1270,9 @@
     if (locked) {
         mLock.unlock();
     }
-    return NO_ERROR;
 }
 
-status_t AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String16>& args)
+void AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -1291,7 +1287,6 @@
             chain->dump(fd, args);
         }
     }
-    return NO_ERROR;
 }
 
 void AudioFlinger::ThreadBase::acquireWakeLock()
@@ -1539,15 +1534,14 @@
     delete [] mMixBuffer;
 }
 
-status_t AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
+void AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
 {
     dumpInternals(fd, args);
     dumpTracks(fd, args);
     dumpEffectChains(fd, args);
-    return NO_ERROR;
 }
 
-status_t AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args)
+void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -1595,11 +1589,9 @@
     FastTrackUnderruns underruns = getFastTrackUnderruns(0);
     fdprintf(fd, "Normal mixer raw underrun counters: partial=%u empty=%u\n",
             underruns.mBitFields.mPartial, underruns.mBitFields.mEmpty);
-
-    return NO_ERROR;
 }
 
-status_t AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
+void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -1623,8 +1615,6 @@
     fdprintf(fd, "Fast track availMask=%#x\n", mFastTrackAvailMask);
 
     dumpBase(fd, args);
-
-    return NO_ERROR;
 }
 
 // Thread virtuals
@@ -3498,7 +3488,7 @@
     return reconfig;
 }
 
-status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
+void AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -3583,8 +3573,6 @@
         AudioWatchdogDump wdCopy = mAudioWatchdogDump;
         wdCopy.dump(fd);
     }
-
-    return NO_ERROR;
 }
 
 uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() const
@@ -6132,9 +6120,12 @@
     if (!mStandby) {
         mInput->stream->common.standby(&mInput->stream->common);
     }
-    mActiveTrack.clear();
 
-    mStartStopCond.broadcast();
+    {
+        Mutex::Autolock _l(mLock);
+        mActiveTrack.clear();
+        mStartStopCond.broadcast();
+    }
 
     releaseWakeLock();
 
@@ -6310,7 +6301,7 @@
             }
             mStartStopCond.wait(mLock);
             // if we have been restarted, recordTrack == mActiveTrack.get() here
-            if (mActiveTrack == 0 || recordTrack != mActiveTrack.get()) {
+            if (exitPending() || mActiveTrack == 0 || recordTrack != mActiveTrack.get()) {
                 mLock.unlock();
                 AudioSystem::stopInput(mId);
                 mLock.lock();
@@ -6340,7 +6331,7 @@
     return NAME_NOT_FOUND;
 }
 
-status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
+void AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -6374,8 +6365,6 @@
 
     dumpBase(fd, args);
     dumpEffectChains(fd, args);
-
-    return NO_ERROR;
 }
 
 // AudioBufferProvider interface
@@ -7954,7 +7943,7 @@
                                         int sessionId)
     : mPinned(sessionId > AUDIO_SESSION_OUTPUT_MIX),
       mThread(thread), mChain(chain), mId(id), mSessionId(sessionId),
-      // mDescriptor is set below
+      mDescriptor(*desc),
       // mConfig is set by configure() and not used before then
       mEffectInterface(NULL),
       mStatus(NO_INIT), mState(IDLE),
@@ -7964,11 +7953,6 @@
 {
     ALOGV("Constructor %p", this);
     int lStatus;
-    if (thread == NULL) {
-        return;
-    }
-
-    memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t));
 
     // create effect engine from effect factory
     mStatus = EffectCreate(&desc->uuid, sessionId, thread->id(), &mEffectInterface);
@@ -8072,7 +8056,7 @@
         mState = DESTROYED;
     }
 
-    return size;
+    return mHandles.size();
 }
 
 // must be called with EffectModule::mLock held
@@ -8625,7 +8609,7 @@
     return enabled;
 }
 
-status_t AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
+void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -8705,8 +8689,6 @@
     if (locked) {
         mLock.unlock();
     }
-
-    return NO_ERROR;
 }
 
 // ----------------------------------------------------------------------------
@@ -9332,7 +9314,7 @@
     return hasControl;
 }
 
-status_t AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args)
+void AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -9366,8 +9348,6 @@
     if (locked) {
         mLock.unlock();
     }
-
-    return NO_ERROR;
 }
 
 // must be called with ThreadBase::mLock held
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index c6f08cd..c9a3c3f 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -277,10 +277,10 @@
     // ro.audio.flinger_standbytime_ms or defaults to kDefaultStandbyTimeInNsecs
     static nsecs_t          mStandbyTimeInNsecs;
 
-    // Internal dump utilites.
-    status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
-    status_t dumpClients(int fd, const Vector<String16>& args);
-    status_t dumpInternals(int fd, const Vector<String16>& args);
+    // Internal dump utilities.
+    void dumpPermissionDenial(int fd, const Vector<String16>& args);
+    void dumpClients(int fd, const Vector<String16>& args);
+    void dumpInternals(int fd, const Vector<String16>& args);
 
     // --- Client ---
     class Client : public RefBase {
@@ -355,8 +355,8 @@
         ThreadBase (const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, audio_devices_t device, type_t type);
         virtual             ~ThreadBase();
 
-        status_t dumpBase(int fd, const Vector<String16>& args);
-        status_t dumpEffectChains(int fd, const Vector<String16>& args);
+        void dumpBase(int fd, const Vector<String16>& args);
+        void dumpEffectChains(int fd, const Vector<String16>& args);
 
         void clearPowerManager();
 
@@ -966,7 +966,7 @@
                         audio_io_handle_t id, audio_devices_t device, type_t type);
         virtual             ~PlaybackThread();
 
-                    status_t    dump(int fd, const Vector<String16>& args);
+                    void        dump(int fd, const Vector<String16>& args);
 
         // Thread virtuals
         virtual     status_t    readyToRun();
@@ -1115,8 +1115,8 @@
 
         void        readOutputParameters();
 
-        virtual status_t    dumpInternals(int fd, const Vector<String16>& args);
-        status_t    dumpTracks(int fd, const Vector<String16>& args);
+        virtual void dumpInternals(int fd, const Vector<String16>& args);
+        void        dumpTracks(int fd, const Vector<String16>& args);
 
         SortedVector< sp<Track> >       mTracks;
         // mStreamTypes[] uses 1 additional stream type internally for the OutputTrack used by DuplicatingThread
@@ -1192,7 +1192,7 @@
         // Thread virtuals
 
         virtual     bool        checkForNewParameters_l();
-        virtual     status_t    dumpInternals(int fd, const Vector<String16>& args);
+        virtual     void        dumpInternals(int fd, const Vector<String16>& args);
 
     protected:
         virtual     mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
@@ -1433,7 +1433,7 @@
                                   AudioSystem::sync_event_t event,
                                   int triggerSession);
                 void        stop(RecordTrack* recordTrack);
-                status_t    dump(int fd, const Vector<String16>& args);
+                void        dump(int fd, const Vector<String16>& args);
                 AudioStreamIn* clearInput();
                 virtual audio_stream_t* stream() const;
 
@@ -1591,7 +1591,7 @@
         void             lock() { mLock.lock(); }
         void             unlock() { mLock.unlock(); }
 
-        status_t         dump(int fd, const Vector<String16>& args);
+        void             dump(int fd, const Vector<String16>& args);
 
     protected:
         friend class AudioFlinger;      // for mHandles
@@ -1779,7 +1779,7 @@
 
         void clearInputBuffer();
 
-        status_t dump(int fd, const Vector<String16>& args);
+        void dump(int fd, const Vector<String16>& args);
 
     protected:
         friend class AudioFlinger;  // for mThread, mEffects
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index 8d4add4..f21a518 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -67,6 +67,7 @@
 status_t Camera2Client::initialize(camera_module_t *module)
 {
     ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
     status_t res;
 
     res = mDevice->initialize(module);
@@ -320,6 +321,7 @@
 
 void Camera2Client::disconnect() {
     ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mICameraLock);
 
     if (mDevice == 0) return;
@@ -338,12 +340,17 @@
         mCaptureStreamId = NO_STREAM;
     }
 
+    if (mRecordingStreamId != NO_STREAM) {
+        mDevice->deleteStream(mRecordingStreamId);
+        mRecordingStreamId = NO_STREAM;
+    }
+
     CameraService::Client::disconnect();
 }
 
 status_t Camera2Client::connect(const sp<ICameraClient>& client) {
     ATRACE_CALL();
-
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mICameraLock);
 
     if (mClientPid != 0 && getCallingPid() != mClientPid) {
@@ -361,6 +368,7 @@
 
 status_t Camera2Client::lock() {
     ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mICameraLock);
     ALOGV("%s: Camera %d: Lock call from pid %d; current client pid %d",
             __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
@@ -381,6 +389,7 @@
 
 status_t Camera2Client::unlock() {
     ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mICameraLock);
     ALOGV("%s: Camera %d: Unlock call from pid %d; current client pid %d",
             __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
@@ -401,6 +410,7 @@
 status_t Camera2Client::setPreviewDisplay(
         const sp<Surface>& surface) {
     ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mICameraLock);
 
     sp<IBinder> binder;
@@ -416,6 +426,7 @@
 status_t Camera2Client::setPreviewTexture(
         const sp<ISurfaceTexture>& surfaceTexture) {
     ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mICameraLock);
 
     sp<IBinder> binder;
@@ -433,6 +444,8 @@
     status_t res;
 
     if (binder == mPreviewSurface) {
+        ALOGV("%s: Camera %d: New window is same as old window",
+                __FUNCTION__, mCameraId);
         return NO_ERROR;
     }
 
@@ -490,6 +503,7 @@
 
 status_t Camera2Client::startPreview() {
     ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mICameraLock);
     return startPreviewLocked();
 }
@@ -556,6 +570,7 @@
 
 void Camera2Client::stopPreview() {
     ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mICameraLock);
     stopPreviewLocked();
 }
@@ -577,6 +592,7 @@
             // TODO: Handle record stop here
         case PREVIEW:
             mDevice->setStreamingRequest(NULL);
+            mDevice->waitUntilDrained();
         case WAITING_FOR_PREVIEW_WINDOW:
             mState = STOPPED;
             break;
@@ -600,6 +616,7 @@
 
 status_t Camera2Client::startRecording() {
     ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mICameraLock);
     status_t res;
     switch (mState) {
@@ -669,6 +686,7 @@
 
 void Camera2Client::stopRecording() {
     ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mICameraLock);
     status_t res;
     switch (mState) {
@@ -843,6 +861,7 @@
 
 status_t Camera2Client::setParameters(const String8& params) {
     ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mICameraLock);
     Mutex::Autolock pl(mParamsLock);
     status_t res;
@@ -1492,10 +1511,12 @@
     {
         Mutex::Autolock icl(mICameraLock);
         // TODO: Signal errors here upstream
+        bool discardData = false;
         if (mState != RECORD && mState != VIDEO_SNAPSHOT) {
-            ALOGE("%s: Camera %d: Recording image buffer produced unexpectedly!",
+            ALOGV("%s: Camera %d: Discarding recording image buffers received after "
+                    "recording done",
                     __FUNCTION__, mCameraId);
-            return;
+            discardData = true;
         }
 
         CpuConsumer::LockedBuffer imgBuffer;
@@ -1509,9 +1530,14 @@
         if (imgBuffer.format != (int)kRecordingFormat) {
             ALOGE("%s: Camera %d: Unexpected recording format: %x",
                     __FUNCTION__, mCameraId, imgBuffer.format);
+            discardData = true;
+        }
+
+        if (discardData) {
             mRecordingConsumer->unlockBuffer(imgBuffer);
             return;
         }
+
         size_t bufferSize = imgBuffer.width * imgBuffer.height * 3 / 2;
 
         if (mRecordingHeap == 0 ||
@@ -2323,6 +2349,9 @@
         }
         if (currentWidth != (uint32_t)mParameters.previewWidth ||
                 currentHeight != (uint32_t)mParameters.previewHeight) {
+            ALOGV("%s: Camera %d: Preview size switch: %d x %d -> %d x %d",
+                    __FUNCTION__, mCameraId, currentWidth, currentHeight,
+                    mParameters.previewWidth, mParameters.previewHeight);
             res = mDevice->waitUntilDrained();
             if (res != OK) {
                 ALOGE("%s: Camera %d: Error waiting for preview to drain: "
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index 54dde80..f42e3a5 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -146,7 +146,7 @@
 }
 
 camera_metadata_t *Camera2Device::info() {
-    ALOGV("%s: E", __FUNCTION__);
+    ALOGVV("%s: E", __FUNCTION__);
 
     return mDeviceInfo;
 }
@@ -268,7 +268,7 @@
 status_t Camera2Device::waitUntilDrained() {
     static const uint32_t kSleepTime = 50000; // 50 ms
     static const uint32_t kMaxSleepTime = 10000000; // 10 s
-
+    ALOGV("%s: E", __FUNCTION__);
     if (mRequestQueue.getBufferCount() ==
             CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS) return INVALID_OPERATION;
 
@@ -642,6 +642,7 @@
         sp<ANativeWindow> consumer,
         uint32_t width, uint32_t height, int format, size_t size) {
     status_t res;
+    ALOGV("%s: E", __FUNCTION__);
 
     if (mState != RELEASED) return INVALID_OPERATION;
     if (consumer == NULL) {