Merge "Fix fast track leak if out of normal track names" 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/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/services/audioflinger/MonoPipe.cpp b/services/audioflinger/MonoPipe.cpp
index fd16e92..6efb8b1 100644
--- a/services/audioflinger/MonoPipe.cpp
+++ b/services/audioflinger/MonoPipe.cpp
@@ -25,9 +25,10 @@
 
 namespace android {
 
-MonoPipe::MonoPipe(size_t maxFrames, NBAIO_Format format, bool writeCanBlock) :
+MonoPipe::MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock) :
         NBAIO_Sink(format),
-        mMaxFrames(roundup(maxFrames)),
+        mReqFrames(reqFrames),
+        mMaxFrames(roundup(reqFrames)),
         mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
         mFront(0),
         mRear(0),
@@ -45,6 +46,7 @@
     if (CC_UNLIKELY(!mNegotiated)) {
         return NEGOTIATE;
     }
+    // uses mMaxFrames not mReqFrames, so allows "over-filling" the pipe beyond requested limit
     ssize_t ret = mMaxFrames - (mRear - android_atomic_acquire_load(&mFront));
     ALOG_ASSERT((0 <= ret) && (ret <= mMaxFrames));
     return ret;
@@ -57,6 +59,7 @@
     }
     size_t totalFramesWritten = 0;
     while (count > 0) {
+        // can't return a negative value, as we already checked for !mNegotiated
         size_t avail = availableToWrite();
         size_t written = avail;
         if (CC_LIKELY(written > count)) {
@@ -84,50 +87,29 @@
         count -= written;
         buffer = (char *) buffer + (written << mBitShift);
         // Simulate blocking I/O by sleeping at different rates, depending on a throttle.
-        // The throttle tries to keep the pipe about 5/8 full on average, with a slight jitter.
-        uint64_t ns;
-        enum {
-            THROTTLE_VERY_FAST, // pipe is (nearly) empty, fill quickly
-            THROTTLE_FAST,      // pipe is normal, fill at slightly faster rate
-            THROTTLE_NOMINAL,   // pipe is normal, fill at nominal rate
-            THROTTLE_SLOW,      // pipe is normal, fill at slightly slower rate
-            THROTTLE_VERY_SLOW, // pipe is (nearly) full, fill slowly
-        } throttle;
-        avail -= written;
-        // FIXME cache these values to avoid re-computation
-        if (avail >= (mMaxFrames * 3) / 4) {
-            throttle = THROTTLE_VERY_FAST;
-        } else if (avail >= mMaxFrames / 2) {
-            throttle = THROTTLE_FAST;
-        } else if (avail >= (mMaxFrames * 3) / 8) {
-            throttle = THROTTLE_NOMINAL;
-        } else if (avail >= mMaxFrames / 4) {
-            throttle = THROTTLE_SLOW;
-        } else {
-            throttle = THROTTLE_VERY_SLOW;
-        }
+        // The throttle tries to keep the pipe about 11/16 full on average, with a slight jitter.
+        uint32_t ns;
         if (written > 0) {
-            // FIXME cache these values also
-            switch (throttle) {
-            case THROTTLE_VERY_FAST:
-            default:
+            size_t filled = (mMaxFrames - avail) + written;
+            // FIXME cache these values to avoid re-computation
+            if (filled <= mReqFrames / 4) {
+                // pipe is (nearly) empty, fill quickly
                 ns = written * ( 500000000 / Format_sampleRate(mFormat));
-                break;
-            case THROTTLE_FAST:
+            } else if (filled <= mReqFrames / 2) {
+                // pipe is normal, fill at slightly faster rate
                 ns = written * ( 750000000 / Format_sampleRate(mFormat));
-                break;
-            case THROTTLE_NOMINAL:
+            } else if (filled <= (mReqFrames * 5) / 8) {
+                // pipe is normal, fill at nominal rate
                 ns = written * (1000000000 / Format_sampleRate(mFormat));
-                break;
-            case THROTTLE_SLOW:
+            } else if (filled <= (mReqFrames * 3) / 4) {
+                // pipe is normal, fill at slightly slower rate
                 ns = written * (1100000000 / Format_sampleRate(mFormat));
-                break;
-            case THROTTLE_VERY_SLOW:
+            } else {
+                // pipe is (nearly) full, fill slowly
                 ns = written * (1250000000 / Format_sampleRate(mFormat));
-                break;
             }
         } else {
-            ns = mMaxFrames * (250000000 / Format_sampleRate(mFormat));
+            ns = mReqFrames * (250000000 / Format_sampleRate(mFormat));
         }
         if (ns > 999999999) {
             ns = 999999999;
diff --git a/services/audioflinger/MonoPipe.h b/services/audioflinger/MonoPipe.h
index 545d6ac..aaaa51f 100644
--- a/services/audioflinger/MonoPipe.h
+++ b/services/audioflinger/MonoPipe.h
@@ -33,11 +33,11 @@
     friend class MonoPipeReader;
 
 public:
-    // maxFrames will be rounded up to a power of 2, and all slots are available. Must be >= 2.
+    // reqFrames will be rounded up to a power of 2, and all slots are available. Must be >= 2.
     // Note: whatever shares this object with another thread needs to do so in an SMP-safe way (like
     // creating it the object before creating the other thread, or storing the object with a
     // release_store). Otherwise the other thread could see a partially-constructed object.
-    MonoPipe(size_t maxFrames, NBAIO_Format format, bool writeCanBlock = false);
+    MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock = false);
     virtual ~MonoPipe();
 
     // NBAIO_Port interface
@@ -58,9 +58,10 @@
 
             // average number of frames present in the pipe under normal conditions.
             // See throttling mechanism in MonoPipe::write()
-            size_t  getAvgFrames() const { return (mMaxFrames * 11) / 16; }
+            size_t  getAvgFrames() const { return (mReqFrames * 11) / 16; }
 
 private:
+    const size_t    mReqFrames;     // as requested in constructor, unrounded
     const size_t    mMaxFrames;     // always a power of 2
     void * const    mBuffer;
     // mFront and mRear will never be separated by more than mMaxFrames.