Merge "Issue 5298399: Lost speech after a crash in gTalk."
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
index 803bffb..a73403b 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -62,12 +62,17 @@
 private:
     // current locale (like "ja_JP"), created/destroyed with strdup()/free()
     char *mLocale;
+    char *mSkipList;
+    int *mSkipIndex;
 
     MediaScanResult doProcessDirectory(
             char *path, int pathRemaining, MediaScannerClient &client, bool noMedia);
     MediaScanResult doProcessDirectoryEntry(
             char *path, int pathRemaining, MediaScannerClient &client, bool noMedia,
             struct dirent* entry, char* fileSpot);
+    void loadSkipList();
+    bool shouldSkipDirectory(char *path);
+
 
     MediaScanner(const MediaScanner &);
     MediaScanner &operator=(const MediaScanner &);
@@ -103,4 +108,3 @@
 }; // namespace android
 
 #endif // MEDIASCANNER_H
-
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index e965f14..b7286e5 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -164,6 +164,8 @@
 
     void sendFormatChange();
 
+    void signalError(OMX_ERRORTYPE error = OMX_ErrorUndefined);
+
     DISALLOW_EVIL_CONSTRUCTORS(ACodec);
 };
 
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 41f8593..19dedfc 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -16,6 +16,7 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaScanner"
+#include <cutils/properties.h>
 #include <utils/Log.h>
 
 #include <media/mediascanner.h>
@@ -26,11 +27,14 @@
 namespace android {
 
 MediaScanner::MediaScanner()
-    : mLocale(NULL) {
+    : mLocale(NULL), mSkipList(NULL), mSkipIndex(NULL) {
+    loadSkipList();
 }
 
 MediaScanner::~MediaScanner() {
     setLocale(NULL);
+    free(mSkipList);
+    free(mSkipIndex);
 }
 
 void MediaScanner::setLocale(const char *locale) {
@@ -47,6 +51,33 @@
     return mLocale;
 }
 
+void MediaScanner::loadSkipList() {
+    mSkipList = (char *)malloc(PROPERTY_VALUE_MAX * sizeof(char));
+    if (mSkipList) {
+      property_get("testing.mediascanner.skiplist", mSkipList, "");
+    }
+    if (!mSkipList || (strlen(mSkipList) == 0)) {
+        free(mSkipList);
+        mSkipList = NULL;
+        return;
+    }
+    mSkipIndex = (int *)malloc(PROPERTY_VALUE_MAX * sizeof(int));
+    if (mSkipIndex) {
+        // dup it because strtok will modify the string
+        char *skipList = strdup(mSkipList);
+        if (skipList) {
+            char * path = strtok(skipList, ",");
+            int i = 0;
+            while (path) {
+                mSkipIndex[i++] = strlen(path);
+                path = strtok(NULL, ",");
+            }
+            mSkipIndex[i] = -1;
+            free(skipList);
+        }
+    }
+}
+
 MediaScanResult MediaScanner::processDirectory(
         const char *path, MediaScannerClient &client) {
     int pathLength = strlen(path);
@@ -75,12 +106,39 @@
     return result;
 }
 
+bool MediaScanner::shouldSkipDirectory(char *path) {
+    if (path && mSkipList && mSkipIndex) {
+        int len = strlen(path);
+        int idx = 0;
+        // track the start position of next path in the comma
+        // separated list obtained from getprop
+        int startPos = 0;
+        while (mSkipIndex[idx] != -1) {
+            // no point to match path name if strlen mismatch
+            if ((len == mSkipIndex[idx])
+                // pick out the path segment from comma separated list
+                // to compare against current path parameter
+                && (strncmp(path, &mSkipList[startPos], len) == 0)) {
+                return true;
+            }
+            startPos += mSkipIndex[idx] + 1; // extra char for the delimiter
+            idx++;
+        }
+    }
+    return false;
+}
+
 MediaScanResult MediaScanner::doProcessDirectory(
         char *path, int pathRemaining, MediaScannerClient &client, bool noMedia) {
     // place to copy file or directory name
     char* fileSpot = path + strlen(path);
     struct dirent* entry;
 
+    if (shouldSkipDirectory(path)) {
+      LOGD("Skipping: %s", path);
+      return MEDIA_SCAN_RESULT_OK;
+    }
+
     // Treat all files as non-media in directories that contain a  ".nomedia" file
     if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
         strcpy(fileSpot, ".nomedia");
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 8f213da..bf83849 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -26,6 +26,9 @@
 
 namespace android {
 
+// static
+const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
+
 NuPlayer::Renderer::Renderer(
         const sp<MediaPlayerBase::AudioSink> &sink,
         const sp<AMessage> &notify)
@@ -43,7 +46,8 @@
       mHasAudio(false),
       mHasVideo(false),
       mSyncQueues(false),
-      mPaused(false) {
+      mPaused(false),
+      mLastPositionUpdateUs(-1ll) {
 }
 
 NuPlayer::Renderer::~Renderer() {
@@ -190,7 +194,7 @@
     mDrainAudioQueuePending = true;
     sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
     msg->setInt32("generation", mAudioQueueGeneration);
-    msg->post(10000);
+    msg->post();
 }
 
 void NuPlayer::Renderer::signalAudioSinkChanged() {
@@ -198,7 +202,6 @@
 }
 
 void NuPlayer::Renderer::onDrainAudioQueue() {
-
     for (;;) {
         if (mAudioQueue.empty()) {
             break;
@@ -562,6 +565,13 @@
     }
 
     int64_t nowUs = ALooper::GetNowUs();
+
+    if (mLastPositionUpdateUs >= 0
+            && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs) {
+        return;
+    }
+    mLastPositionUpdateUs = nowUs;
+
     int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs;
 
     sp<AMessage> notify = mNotify->dup();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 2713031..3a641a2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -74,6 +74,8 @@
         status_t mFinalResult;
     };
 
+    static const int64_t kMinPositionUpdateDelayUs;
+
     sp<MediaPlayerBase::AudioSink> mAudioSink;
     sp<AMessage> mNotify;
     List<QueueEntry> mAudioQueue;
@@ -98,6 +100,8 @@
 
     bool mPaused;
 
+    int64_t mLastPositionUpdateUs;
+
     void onDrainAudioQueue();
     void postDrainAudioQueue();
 
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index e9dc61c..2ba2273 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1131,6 +1131,13 @@
     mSentFormat = true;
 }
 
+void ACodec::signalError(OMX_ERRORTYPE error) {
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", ACodec::kWhatError);
+    notify->setInt32("omx-error", error);
+    notify->post();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
@@ -1252,10 +1259,7 @@
 
     LOGE("[%s] ERROR(0x%08lx)", mCodec->mComponentName.c_str(), data1);
 
-    sp<AMessage> notify = mCodec->mNotify->dup();
-    notify->setInt32("what", ACodec::kWhatError);
-    notify->setInt32("omx-error", data1);
-    notify->post();
+    mCodec->signalError((OMX_ERRORTYPE)data1);
 
     return true;
 }
@@ -1548,12 +1552,14 @@
             && msg->findInt32("render", &render) && render != 0) {
         // The client wants this buffer to be rendered.
 
-        CHECK_EQ(mCodec->mNativeWindow->queueBuffer(
+        if (mCodec->mNativeWindow->queueBuffer(
                     mCodec->mNativeWindow.get(),
-                    info->mGraphicBuffer.get()),
-                 0);
-
-        info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
+                    info->mGraphicBuffer.get()) == OK) {
+            info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
+        } else {
+            mCodec->signalError();
+            info->mStatus = BufferInfo::OWNED_BY_US;
+        }
     } else {
         info->mStatus = BufferInfo::OWNED_BY_US;
     }
@@ -1692,11 +1698,7 @@
     if (node == NULL) {
         LOGE("Unable to instantiate a decoder for type '%s'.", mime.c_str());
 
-        sp<AMessage> notify = mCodec->mNotify->dup();
-        notify->setInt32("what", ACodec::kWhatError);
-        notify->setInt32("omx-error", OMX_ErrorComponentNotFound);
-        notify->post();
-
+        mCodec->signalError(OMX_ErrorComponentNotFound);
         return;
     }
 
@@ -1744,10 +1746,7 @@
              "(error 0x%08x)",
              err);
 
-        sp<AMessage> notify = mCodec->mNotify->dup();
-        notify->setInt32("what", ACodec::kWhatError);
-        notify->setInt32("omx-error", OMX_ErrorUndefined);
-        notify->post();
+        mCodec->signalError();
     }
 }
 
@@ -2063,10 +2062,7 @@
                          "port reconfiguration (error 0x%08x)",
                          err);
 
-                    sp<AMessage> notify = mCodec->mNotify->dup();
-                    notify->setInt32("what", ACodec::kWhatError);
-                    notify->setInt32("omx-error", OMX_ErrorUndefined);
-                    notify->post();
+                    mCodec->signalError();
                 }
 
                 return true;
diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp
index 6313ca3..4e46414 100644
--- a/media/libstagefright/AVIExtractor.cpp
+++ b/media/libstagefright/AVIExtractor.cpp
@@ -117,14 +117,12 @@
         }
     }
 
-    int64_t timeUs =
-        (mSampleIndex * 1000000ll * mTrack.mRate) / mTrack.mScale;
-
     off64_t offset;
     size_t size;
     bool isKey;
+    int64_t timeUs;
     status_t err = mExtractor->getSampleInfo(
-            mTrackIndex, mSampleIndex, &offset, &size, &isKey);
+            mTrackIndex, mSampleIndex, &offset, &size, &isKey, &timeUs);
 
     ++mSampleIndex;
 
@@ -396,6 +394,8 @@
     uint32_t rate = U32LE_AT(&data[20]);
     uint32_t scale = U32LE_AT(&data[24]);
 
+    uint32_t sampleSize = U32LE_AT(&data[44]);
+
     const char *mime = NULL;
     Track::Kind kind = Track::OTHER;
 
@@ -427,6 +427,7 @@
     track->mMeta = meta;
     track->mRate = rate;
     track->mScale = scale;
+    track->mBytesPerSample = sampleSize;
     track->mKind = kind;
     track->mNumSyncSamples = 0;
     track->mThumbnailSampleSize = 0;
@@ -612,11 +613,12 @@
         off64_t offset;
         size_t size;
         bool isKey;
-        status_t err = getSampleInfo(0, 0, &offset, &size, &isKey);
+        int64_t timeUs;
+        status_t err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
 
         if (err != OK) {
             mOffsetsAreAbsolute = !mOffsetsAreAbsolute;
-            err = getSampleInfo(0, 0, &offset, &size, &isKey);
+            err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
 
             if (err != OK) {
                 return err;
@@ -630,8 +632,9 @@
     for (size_t i = 0; i < mTracks.size(); ++i) {
         Track *track = &mTracks.editItemAt(i);
 
-        int64_t durationUs =
-            (track->mSamples.size() * 1000000ll * track->mRate) / track->mScale;
+        int64_t durationUs;
+        CHECK_EQ((status_t)OK,
+                 getSampleTime(i, track->mSamples.size() - 1, &durationUs));
 
         LOGV("track %d duration = %.2f secs", i, durationUs / 1E6);
 
@@ -645,9 +648,10 @@
 
         if (!strncasecmp("video/", mime.c_str(), 6)
                 && track->mThumbnailSampleIndex >= 0) {
-            int64_t thumbnailTimeUs =
-                (track->mThumbnailSampleIndex * 1000000ll * track->mRate)
-                    / track->mScale;
+            int64_t thumbnailTimeUs;
+            CHECK_EQ((status_t)OK,
+                     getSampleTime(i, track->mThumbnailSampleIndex,
+                                   &thumbnailTimeUs));
 
             track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
 
@@ -659,6 +663,21 @@
                 }
             }
         }
+
+        if (track->mBytesPerSample != 0) {
+            // Assume all chunks are the same size for now.
+
+            off64_t offset;
+            size_t size;
+            bool isKey;
+            int64_t sampleTimeUs;
+            CHECK_EQ((status_t)OK,
+                     getSampleInfo(
+                         i, 0,
+                         &offset, &size, &isKey, &sampleTimeUs));
+
+            track->mRate *= size / track->mBytesPerSample;
+        }
     }
 
     mFoundIndex = true;
@@ -720,7 +739,9 @@
     off64_t offset;
     size_t size;
     bool isKey;
-    status_t err = getSampleInfo(trackIndex, 0, &offset, &size, &isKey);
+    int64_t timeUs;
+    status_t err =
+        getSampleInfo(trackIndex, 0, &offset, &size, &isKey, &timeUs);
 
     if (err != OK) {
         return err;
@@ -762,7 +783,8 @@
 
 status_t AVIExtractor::getSampleInfo(
         size_t trackIndex, size_t sampleIndex,
-        off64_t *offset, size_t *size, bool *isKey) {
+        off64_t *offset, size_t *size, bool *isKey,
+        int64_t *sampleTimeUs) {
     if (trackIndex >= mTracks.size()) {
         return -ERANGE;
     }
@@ -801,9 +823,20 @@
 
     *isKey = info.mIsKey;
 
+    *sampleTimeUs = (sampleIndex * 1000000ll * track.mRate) / track.mScale;
+
     return OK;
 }
 
+status_t AVIExtractor::getSampleTime(
+        size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs) {
+    off64_t offset;
+    size_t size;
+    bool isKey;
+    return getSampleInfo(
+            trackIndex, sampleIndex, &offset, &size, &isKey, sampleTimeUs);
+}
+
 status_t AVIExtractor::getSampleIndexAtTime(
         size_t trackIndex,
         int64_t timeUs, MediaSource::ReadOptions::SeekMode mode,
@@ -911,7 +944,11 @@
 
     if (!memcmp(tmp, "RIFF", 4) && !memcmp(&tmp[8], "AVI ", 4)) {
         mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_AVI);
-        *confidence = 0.2;
+
+        // Just a tad over the mp3 extractor's confidence, since
+        // these .avi files may contain .mp3 content that otherwise would
+        // mistakenly lead to us identifying the entire file as a .mp3 file.
+        *confidence = 0.21;
 
         return true;
     }
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index fb49d7b..9ab470b 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -50,7 +50,7 @@
 
 // Treat time out as an error if we have not received any output
 // buffers after 3 seconds.
-const static int64_t kBufferFilledEventTimeOutUs = 3000000000LL;
+const static int64_t kBufferFilledEventTimeOutNs = 3000000000LL;
 
 struct CodecInfo {
     const char *mime;
@@ -2325,9 +2325,14 @@
         {
             CODEC_LOGV("OMX_EventPortSettingsChanged(port=%ld, data2=0x%08lx)",
                        data1, data2);
-            CHECK(mFilledBuffers.empty());
 
             if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
+                // There is no need to check whether mFilledBuffers is empty or not
+                // when the OMX_EventPortSettingsChanged is not meant for reallocating
+                // the output buffers.
+                if (data1 == kPortIndexOutput) {
+                    CHECK(mFilledBuffers.empty());
+                }
                 onPortSettingsChanged(data1);
             } else if (data1 == kPortIndexOutput &&
                         (data2 == OMX_IndexConfigCommonOutputCrop ||
@@ -3220,7 +3225,7 @@
         // for video encoding.
         return mBufferFilled.wait(mLock);
     }
-    status_t err = mBufferFilled.waitRelative(mLock, kBufferFilledEventTimeOutUs);
+    status_t err = mBufferFilled.waitRelative(mLock, kBufferFilledEventTimeOutNs);
     if (err != OK) {
         CODEC_LOGE("Timed out waiting for output buffers: %d/%d",
             countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
diff --git a/media/libstagefright/include/AVIExtractor.h b/media/libstagefright/include/AVIExtractor.h
index 375a94d..b575347 100644
--- a/media/libstagefright/include/AVIExtractor.h
+++ b/media/libstagefright/include/AVIExtractor.h
@@ -54,6 +54,11 @@
         uint32_t mRate;
         uint32_t mScale;
 
+        // If bytes per sample == 0, each chunk represents a single sample,
+        // otherwise each chunk should me a multiple of bytes-per-sample in
+        // size.
+        uint32_t mBytesPerSample;
+
         enum Kind {
             AUDIO,
             VIDEO,
@@ -84,7 +89,11 @@
 
     status_t getSampleInfo(
             size_t trackIndex, size_t sampleIndex,
-            off64_t *offset, size_t *size, bool *isKey);
+            off64_t *offset, size_t *size, bool *isKey,
+            int64_t *sampleTimeUs);
+
+    status_t getSampleTime(
+            size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs);
 
     status_t getSampleIndexAtTime(
             size_t trackIndex,
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 94efa74..a58f64c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -87,6 +87,8 @@
 // RecordThread loop sleep time upon application overrun or audio HAL read error
 static const int kRecordThreadSleepUs = 5000;
 
+static const nsecs_t kSetParametersTimeout = seconds(2);
+
 // ----------------------------------------------------------------------------
 
 static bool recordingAllowed() {
@@ -1032,7 +1034,7 @@
     mWaitWorkCV.signal();
     // wait condition with timeout in case the thread loop has exited
     // before the request could be processed
-    if (mParamCond.waitRelative(mLock, seconds(2)) == NO_ERROR) {
+    if (mParamCond.waitRelative(mLock, kSetParametersTimeout) == NO_ERROR) {
         status = mParamStatus;
         mWaitWorkCV.signal();
     } else {
@@ -2349,7 +2351,9 @@
 
         mParamStatus = status;
         mParamCond.signal();
-        mWaitWorkCV.wait(mLock);
+        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+        // already timed out waiting for the status and will never signal the condition.
+        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
     }
     return reconfig;
 }
@@ -2828,7 +2832,9 @@
 
         mParamStatus = status;
         mParamCond.signal();
-        mWaitWorkCV.wait(mLock);
+        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+        // already timed out waiting for the status and will never signal the condition.
+        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
     }
     return reconfig;
 }
@@ -4669,7 +4675,9 @@
 
         mParamStatus = status;
         mParamCond.signal();
-        mWaitWorkCV.wait(mLock);
+        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+        // already timed out waiting for the status and will never signal the condition.
+        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
     }
     return reconfig;
 }