Merge "Pipe throttle based on requested frame count" into jb-dev
diff --git a/libvideoeditor/vss/src/M4VSS3GPP_Clip.c b/libvideoeditor/vss/src/M4VSS3GPP_Clip.c
index a79128d..40612f3 100755
--- a/libvideoeditor/vss/src/M4VSS3GPP_Clip.c
+++ b/libvideoeditor/vss/src/M4VSS3GPP_Clip.c
@@ -167,6 +167,47 @@
     return M4NO_ERROR;
 }
 
+// This method maps the frequency value to a string.
+static const char* freqToString(int freq) {
+    switch (freq) {
+    case 8000:
+        return "_8000";
+    case 11025:
+        return "_11025";
+    case 12000:
+        return "_12000";
+    case 16000:
+        return "_16000";
+    case 22050:
+        return "_22050";
+    case 24000:
+        return "_24000";
+    case 32000:
+        return "_32000";
+    case 44100:
+        return "_44100";
+    case 48000:
+        return "_48000";
+    default:
+        M4OSA_TRACE1_1("Unsupported sampling rate: %d Hz", freq);
+        return NULL;
+    }
+}
+
+// This method maps the number of channel value to
+// a string that will be part of a file name extension
+static const char* channelToStringAndFileExt(int channels) {
+    switch (channels) {
+    case 1:
+        return "_1.pcm";
+    case 2:
+        return "_2.pcm";
+    default:
+        M4OSA_TRACE1_1("Unsupported %d channels", channels);
+        return NULL;
+    }
+}
+
 /* Note: if the clip is opened in fast mode, it can only be used for analysis and nothing else. */
 M4OSA_ERR M4VSS3GPP_intClipOpen( M4VSS3GPP_ClipContext *pClipCtxt,
                                 M4VSS3GPP_ClipSettings *pClipSettings, M4OSA_Bool bSkipAudioTrack,
@@ -185,7 +226,6 @@
 #endif /* M4VSS_ENABLE_EXTERNAL_DECODERS */
 
     M4DECODER_OutputFilter FilterOption;
-    M4OSA_Char pTempFile[100];
 
     /**
     *    Check input parameters */
@@ -303,73 +343,45 @@
             }
         }
     }
-    if(pClipCtxt->pSettings->FileType == M4VIDEOEDITING_kFileType_PCM)
-    {
+    if (pClipCtxt->pSettings->FileType == M4VIDEOEDITING_kFileType_PCM) {
+        // Compose the temp filename with sample rate and channel information.
+        const char* freqStr = freqToString(
+                    pClipCtxt->pSettings->ClipProperties.uiSamplingFrequency);
 
-
-
-
-        M4OSA_chrNCopy(pTempFile,pClipSettings->pFile,strlen(pClipSettings->pFile));
-
-
-    switch (pClipCtxt->pSettings->ClipProperties.uiSamplingFrequency)
-    {
-        case 8000:
-        strncat((char *)pTempFile,(const char *)"_8000",6);
-        break;
-        case 11025:
-        strncat((char *)pTempFile,(const char *)"_11025",6);
-        break;
-        case 12000:
-        strncat((char *)pTempFile,(const char *)"_12000",6);
-        break;
-        case 16000:
-        strncat((char *)pTempFile,(const char *)"_16000",6);
-        break;
-        case 22050:
-        strncat((char *)pTempFile,(const char *)"_22050",6);
-        break;
-        case 24000:
-        strncat((char *)pTempFile,(const char *)"_24000",6);
-        break;
-        case 32000:
-        strncat((char *)pTempFile,(const char *)"_32000",6);
-        break;
-        case 44100:
-        strncat((char *)pTempFile,(const char *)"_44100",6);
-        break;
-        case 48000:
-        strncat((char *)pTempFile,(const char *)"_48000",6);
-        break;
-        default:
-            M4OSA_TRACE1_1("M4VSS3GPP_intClipOpen: invalid input for BG tracksampling \
-                frequency (%d Hz), returning M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_SAMPLING_FREQUENCY"\
-                    ,pClipCtxt->pSettings->ClipProperties.uiSamplingFrequency );
+        if (freqStr == NULL) {
             return M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_SAMPLING_FREQUENCY;
-    }
-
-
-
-        //M4OSA_chrNCat(pTempFile,
-        //    itoa(pClipCtxt->pSettings->ClipProperties.uiSamplingFrequency),5);
-        switch(pClipCtxt->pSettings->ClipProperties.uiNbChannels)
-        {
-            case 1:
-                strncat((char *)pTempFile,(const char *)"_1.pcm",6);
-            break;
-            case 2:
-                strncat((char *)pTempFile,(const char *)"_2.pcm",6);
-            break;
-            default:
-            M4OSA_TRACE1_1("M4VSS3GPP_intClipOpen: invalid input for BG track no.\
-                 of channels (%d ), returning M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_NB_OF_CHANNELS",\
-                    pClipCtxt->pSettings->ClipProperties.uiNbChannels);
-            return    M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_NB_OF_CHANNELS;
         }
-        //M4OSA_chrNCat(pTempFile,itoa(pClipCtxt->pSettings->ClipProperties.uiNbChannels),1);
+
+        const char* chanStr = channelToStringAndFileExt(
+                    pClipCtxt->pSettings->ClipProperties.uiNbChannels);
+
+        if (chanStr == NULL) {
+                return M4VSS3GPP_WAR_INCOMPATIBLE_AUDIO_NB_OF_CHANNELS;
+        }
+
+        // Allocate one byte more to hold the null terminator
+        M4OSA_UInt32 length =
+            strlen(pClipSettings->pFile) + strlen(freqStr) + strlen(chanStr) + 1;
+
+        char* pTempFile = (char *) malloc(length);
+        if (pTempFile == NULL) {
+            M4OSA_TRACE1_1("M4VSS3GPP_intClipOpen(): malloc %d bytes fail",length);
+            return M4ERR_ALLOC;
+        }
+        memset(pTempFile, 0, length);
+        memcpy(pTempFile, pClipSettings->pFile, strlen(pClipSettings->pFile));
+        strncat(pTempFile, freqStr, strlen(freqStr));
+        strncat(pTempFile, chanStr, strlen(chanStr));
 
         err = pClipCtxt->ShellAPI.m_pReader->m_pFctOpen( pClipCtxt->pReaderContext, pTempFile);
-
+        if (pTempFile != NULL) {
+            free(pTempFile);
+            pTempFile = NULL;
+        }
+        if ( M4NO_ERROR != err ) {
+            M4OSA_TRACE1_1("M4VSS3GPP_intClipOpen(): open pcm file returns error : 0x%x", err);
+            return err;
+        }
     }
     else
     {
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp
index c4c4d84..5026073 100755
--- a/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditor3gpReader.cpp
@@ -1867,6 +1867,28 @@
             }
             err = VideoEditor3gpReader_getNextAu(pC, (*pStreamHandler),
                 (M4_AccessUnit*)pUserData->m_pFirstAU);
+
+            /*
+             * 1. "M4WAR_NO_MORE_AU == err" indicates that there is no more
+             * access unit from the current track. In other words, there
+             * is only a single access unit from the current track, and
+             * the parsing of this track has reached EOS. The reason why
+             * the first access unit needs to be parsed here is because for
+             * some audio codec (like AAC), the very first access unit
+             * must be decoded before its configuration/encoding parameters
+             * (such as # of channels and sample rate) can be correctly
+             * determined.
+             *
+             * 2. "trackCount > pC->mCurrTrack" indicates that there are other
+             * tracks to be parsed, in addition to the current track.
+             *
+             * When both conditions 1 & 2 hold, other tracks should be
+             * parsed. Thus, we should not bail out.
+             */
+            if (M4WAR_NO_MORE_AU == err && trackCount > pC->mCurrTrack) {
+                err = M4NO_ERROR;
+            }
+
             if (M4NO_ERROR != err) {
                 goto Error;
             }
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 5e6cd51..e234532 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1019,13 +1019,6 @@
         cblk->lock.unlock();
     }
 
-    // restart track if it was disabled by audioflinger due to previous underrun
-    if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) {
-        android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags);
-        ALOGW("obtainBuffer() track %p disabled, restarting", this);
-        mAudioTrack->start();
-    }
-
     cblk->waitTimeMs = 0;
 
     if (framesReq > framesAvail) {
@@ -1057,6 +1050,14 @@
 {
     AutoMutex lock(mLock);
     mCblk->stepUser(audioBuffer->frameCount);
+    if (audioBuffer->frameCount > 0) {
+        // restart track if it was disabled by audioflinger due to previous underrun
+        if (mActive && (mCblk->flags & CBLK_DISABLED_MSK)) {
+            android_atomic_and(~CBLK_DISABLED_ON, &mCblk->flags);
+            ALOGW("releaseBuffer() track %p disabled, restarting", this);
+            mAudioTrack->start();
+        }
+    }
 }
 
 // -------------------------------------------------------------------------
@@ -1077,6 +1078,10 @@
 
     ALOGV("write %p: %d bytes, mActive=%d", this, userSize, mActive);
 
+    if (userSize == 0) {
+        return 0;
+    }
+
     // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
     // while we are accessing the cblk
     mLock.lock();
@@ -1157,14 +1162,18 @@
 status_t TimedAudioTrack::queueTimedBuffer(const sp<IMemory>& buffer,
                                            int64_t pts)
 {
-    // restart track if it was disabled by audioflinger due to previous underrun
-    if (mActive && (mCblk->flags & CBLK_DISABLED_MSK)) {
-        android_atomic_and(~CBLK_DISABLED_ON, &mCblk->flags);
-        ALOGW("queueTimedBuffer() track %p disabled, restarting", this);
-        mAudioTrack->start();
+    status_t status = mAudioTrack->queueTimedBuffer(buffer, pts);
+    {
+        AutoMutex lock(mLock);
+        // restart track if it was disabled by audioflinger due to previous underrun
+        if (buffer->size() != 0 && status == NO_ERROR &&
+                mActive && (mCblk->flags & CBLK_DISABLED_MSK)) {
+            android_atomic_and(~CBLK_DISABLED_ON, &mCblk->flags);
+            ALOGW("queueTimedBuffer() track %p disabled, restarting", this);
+            mAudioTrack->start();
+        }
     }
-
-    return mAudioTrack->queueTimedBuffer(buffer, pts);
+    return status;
 }
 
 status_t TimedAudioTrack::setMediaTimeTransform(const LinearTransform& xform,
@@ -1276,6 +1285,7 @@
             usleep(WAIT_PERIOD_MS*1000);
             break;
         }
+
         if (writtenSize > reqSize) writtenSize = reqSize;
 
         if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 892da92..0749254 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -753,19 +753,23 @@
 
         if ((mFlags & PLAYING) && !eos
                 && (cachedDurationUs < kLowWaterMarkUs)) {
-            ALOGI("cache is running low (%.2f secs) , pausing.",
-                 cachedDurationUs / 1E6);
             modifyFlags(CACHE_UNDERRUN, SET);
-            pause_l();
-            ensureCacheIsFetching_l();
-            sendCacheStats();
+            if (mWVMExtractor == NULL) {
+                ALOGI("cache is running low (%.2f secs) , pausing.",
+                      cachedDurationUs / 1E6);
+                pause_l();
+                ensureCacheIsFetching_l();
+                sendCacheStats();
+            }
             notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
         } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
             if (mFlags & CACHE_UNDERRUN) {
-                ALOGI("cache has filled up (%.2f secs), resuming.",
-                     cachedDurationUs / 1E6);
                 modifyFlags(CACHE_UNDERRUN, CLEAR);
-                play_l();
+                if (mWVMExtractor == NULL) {
+                    ALOGI("cache has filled up (%.2f secs), resuming.",
+                          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",
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 8dbff9e..ff95f9f 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -293,12 +293,18 @@
         info->mOwnedByUs = false;
         notifyEmptyBufferDone(header);
 
-        maybeConfigureDownmix();
-        ALOGI("Initially configuring decoder: %d Hz, %d channels",
-              mStreamInfo->sampleRate,
-              mStreamInfo->numChannels);
-        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
-        mOutputPortSettingsChange = AWAITING_DISABLED;
+        // Only send out port settings changed event if both sample rate
+        // and numChannels are valid.
+        if (mStreamInfo->sampleRate && mStreamInfo->numChannels) {
+            maybeConfigureDownmix();
+            ALOGI("Initially configuring decoder: %d Hz, %d channels",
+                mStreamInfo->sampleRate,
+                mStreamInfo->numChannels);
+
+            notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+            mOutputPortSettingsChange = AWAITING_DISABLED;
+        }
+
         return;
     }
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 57d7089..eea3cd2 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -3147,6 +3147,13 @@
                 mixerStatus = MIXER_TRACKS_READY;
             }
         } else {
+            // clear effect chain input buffer if an active track underruns to avoid sending
+            // previous audio buffer again to effects
+            chain = getEffectChain_l(track->sessionId());
+            if (chain != 0) {
+                chain->clearInputBuffer();
+            }
+
             //ALOGV("track %d u=%08x, s=%08x [NOT READY] on thread %p", name, cblk->user, cblk->server, this);
             if ((track->sharedBuffer() != 0) || track->isTerminated() ||
                     track->isStopped() || track->isPaused()) {
@@ -3661,6 +3668,12 @@
             mActiveTrack = t;
             mixerStatus = MIXER_TRACKS_READY;
         } else {
+            // clear effect chain input buffer if an active track underruns to avoid sending
+            // previous audio buffer again to effects
+            if (!mEffectChains.isEmpty()) {
+                mEffectChains[0]->clearInputBuffer();
+            }
+
             //ALOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
             if (track->isTerminated() || track->isStopped() || track->isPaused()) {
                 // We have consumed all the buffers of this track.
@@ -8978,6 +8991,25 @@
     return 0;
 }
 
+void AudioFlinger::EffectChain::clearInputBuffer()
+{
+    Mutex::Autolock _l(mLock);
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread == 0) {
+        ALOGW("clearInputBuffer(): cannot promote mixer thread");
+        return;
+    }
+    clearInputBuffer_l(thread);
+}
+
+// Must be called with EffectChain::mLock locked
+void AudioFlinger::EffectChain::clearInputBuffer_l(sp<ThreadBase> thread)
+{
+    size_t numSamples = thread->frameCount() * thread->channelCount();
+    memset(mInBuffer, 0, numSamples * sizeof(int16_t));
+
+}
+
 // Must be called with EffectChain::mLock locked
 void AudioFlinger::EffectChain::process_l()
 {
@@ -9002,8 +9034,7 @@
             // if no track is active and the effect tail has not been rendered,
             // the input buffer must be cleared here as the mixer process will not do it
             if (tracksOnSession || mTailBufferCount > 0) {
-                size_t numSamples = thread->frameCount() * thread->channelCount();
-                memset(mInBuffer, 0, numSamples * sizeof(int16_t));
+                clearInputBuffer_l(thread);
                 if (mTailBufferCount > 0) {
                     mTailBufferCount--;
                 }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 51cbae7..19390b1 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -1717,6 +1717,8 @@
         void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
                                               bool enabled);
 
+        void clearInputBuffer();
+
         status_t dump(int fd, const Vector<String16>& args);
 
     protected:
@@ -1744,6 +1746,8 @@
         // types or implementations from the suspend/restore mechanism.
         bool isEffectEligibleForSuspend(const effect_descriptor_t& desc);
 
+        void clearInputBuffer_l(sp<ThreadBase> thread);
+
         wp<ThreadBase> mThread;     // parent mixer thread
         Mutex mLock;                // mutex protecting effect list
         Vector< sp<EffectModule> > mEffects; // list of effect modules