Merge "NuPlayer: Fix flush mode decoder error handling" into lmp-dev
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index da4c20c..df0dc58 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -267,7 +267,8 @@
             bool encoder,
             int32_t numChannels, int32_t sampleRate, int32_t bitRate,
             int32_t aacProfile, bool isADTS, int32_t sbrMode,
-            int32_t maxOutputChannelCount, const drcParams_t& drc);
+            int32_t maxOutputChannelCount, const drcParams_t& drc,
+            int32_t pcmLimiterEnable);
 
     status_t setupAC3Codec(bool encoder, int32_t numChannels, int32_t sampleRate);
 
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 8000e84..3630263 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -34,6 +34,7 @@
 struct AString;
 struct IMediaHTTPService;
 class String8;
+struct HTTPBase;
 
 class DataSource : public RefBase {
 public:
@@ -48,7 +49,10 @@
             const sp<IMediaHTTPService> &httpService,
             const char *uri,
             const KeyedVector<String8, String8> *headers = NULL,
-            String8 *contentType = NULL);
+            String8 *contentType = NULL,
+            HTTPBase *httpSource = NULL);
+
+    static sp<DataSource> CreateMediaHTTP(const sp<IMediaHTTPService> &httpService);
 
     DataSource() {}
 
diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp
index 14b31ec..d3b4a35 100644
--- a/media/img_utils/src/DngUtils.cpp
+++ b/media/img_utils/src/DngUtils.cpp
@@ -229,7 +229,9 @@
     err = mEndianOut.write(version, 0, NELEMS(version));
     if (err != OK) return err;
 
-    uint32_t flags = FLAG_OPTIONAL | FLAG_OPTIONAL_FOR_PREVIEW;
+    // Do not include optional flag for preview, as this can have a large effect on the output.
+    uint32_t flags = FLAG_OPTIONAL;
+
     err = mEndianOut.write(&flags, 0, 1);
     if (err != OK) return err;
 
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index baf211b..6859a1a 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -36,6 +36,7 @@
 #include "../../libstagefright/include/DRMExtractor.h"
 #include "../../libstagefright/include/NuCachedSource2.h"
 #include "../../libstagefright/include/WVMExtractor.h"
+#include "../../libstagefright/include/HTTPBase.h"
 
 namespace android {
 
@@ -64,6 +65,7 @@
     mAudioTimeUs = 0;
     mVideoTimeUs = 0;
     mHTTPService.clear();
+    mHttpSource.clear();
     mUri.clear();
     mUriHeaders.clear();
     mFd = -1;
@@ -285,10 +287,23 @@
     // delayed data source creation
     if (mDataSource == NULL) {
         if (!mUri.empty()) {
-            mIsWidevine = !strncasecmp(mUri.c_str(), "widevine://", 11);
+            const char* uri = mUri.c_str();
+            mIsWidevine = !strncasecmp(uri, "widevine://", 11);
+
+            if (!strncasecmp("http://", uri, 7)
+                    || !strncasecmp("https://", uri, 8)
+                    || mIsWidevine) {
+                mHttpSource = DataSource::CreateMediaHTTP(mHTTPService);
+                if (mHttpSource == NULL) {
+                    ALOGE("Failed to create http source!");
+                    notifyPreparedAndCleanup(UNKNOWN_ERROR);
+                    return;
+                }
+            }
 
             mDataSource = DataSource::CreateFromURI(
-                   mHTTPService, mUri.c_str(), &mUriHeaders, &mContentType);
+                   mHTTPService, uri, &mUriHeaders, &mContentType,
+                   static_cast<HTTPBase *>(mHttpSource.get()));
         } else {
             // set to false first, if the extractor
             // comes back as secure, set it to true then.
@@ -361,6 +376,7 @@
         mSniffedMIME = "";
         mDataSource.clear();
         mCachedSource.clear();
+        mHttpSource.clear();
 
         cancelPollBuffering();
     }
@@ -487,6 +503,8 @@
         if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
             static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
         }
+    } else if (mHttpSource != NULL) {
+        static_cast<HTTPBase *>(mHttpSource.get())->disconnect();
     }
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 1741f27..f8601ea 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -127,6 +127,7 @@
 
     sp<DataSource> mDataSource;
     sp<NuCachedSource2> mCachedSource;
+    sp<DataSource> mHttpSource;
     sp<WVMExtractor> mWVMExtractor;
     sp<MetaData> mFileMeta;
     DrmManagerClient *mDrmManagerClient;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 8313da6..7e5087f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -20,6 +20,8 @@
 
 #include "NuPlayerRenderer.h"
 
+#include <cutils/properties.h>
+
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -39,6 +41,16 @@
 // static
 const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
 
+static bool sFrameAccurateAVsync = false;
+
+static void readProperties() {
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("persist.sys.media.avsync", value, NULL)) {
+        sFrameAccurateAVsync =
+            !strcmp("1", value) || !strcasecmp("true", value);
+    }
+}
+
 NuPlayer::Renderer::Renderer(
         const sp<MediaPlayerBase::AudioSink> &sink,
         const sp<AMessage> &notify,
@@ -68,6 +80,7 @@
       mVideoLateByUs(0ll),
       mAudioOffloadPauseTimeoutGeneration(0),
       mAudioOffloadTornDown(false) {
+    readProperties();
 }
 
 NuPlayer::Renderer::~Renderer() {
@@ -576,6 +589,11 @@
 
     ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs);
     // post 2 display refreshes before rendering is due
+    // FIXME currently this increases power consumption, so unless frame-accurate
+    // AV sync is requested, post closer to required render time (at 0.63 vsyncs)
+    if (!sFrameAccurateAVsync) {
+        twoVsyncsUs >>= 4;
+    }
     msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0);
 
     mDrainVideoQueuePending = true;
@@ -976,6 +994,8 @@
 }
 
 void NuPlayer::Renderer::onResume() {
+    readProperties();
+
     if (!mPaused) {
         return;
     }
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 4589ed1..d6fba98 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1359,6 +1359,7 @@
             int32_t isADTS, aacProfile;
             int32_t sbrMode;
             int32_t maxOutputChannelCount;
+            int32_t pcmLimiterEnable;
             drcParams_t drc;
             if (!msg->findInt32("is-adts", &isADTS)) {
                 isADTS = 0;
@@ -1373,6 +1374,10 @@
             if (!msg->findInt32("aac-max-output-channel_count", &maxOutputChannelCount)) {
                 maxOutputChannelCount = -1;
             }
+            if (!msg->findInt32("aac-pcm-limiter-enable", &pcmLimiterEnable)) {
+                // value is unknown
+                pcmLimiterEnable = -1;
+            }
             if (!msg->findInt32("aac-encoded-target-level", &drc.encodedTargetLevel)) {
                 // value is unknown
                 drc.encodedTargetLevel = -1;
@@ -1396,7 +1401,8 @@
 
             err = setupAACCodec(
                     encoder, numChannels, sampleRate, bitRate, aacProfile,
-                    isADTS != 0, sbrMode, maxOutputChannelCount, drc);
+                    isADTS != 0, sbrMode, maxOutputChannelCount, drc,
+                    pcmLimiterEnable);
         }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
         err = setupAMRCodec(encoder, false /* isWAMR */, bitRate);
@@ -1561,7 +1567,8 @@
 status_t ACodec::setupAACCodec(
         bool encoder, int32_t numChannels, int32_t sampleRate,
         int32_t bitRate, int32_t aacProfile, bool isADTS, int32_t sbrMode,
-        int32_t maxOutputChannelCount, const drcParams_t& drc) {
+        int32_t maxOutputChannelCount, const drcParams_t& drc,
+        int32_t pcmLimiterEnable) {
     if (encoder && isADTS) {
         return -EINVAL;
     }
@@ -1691,6 +1698,7 @@
     presentation.nHeavyCompression = drc.heavyCompression;
     presentation.nTargetReferenceLevel = drc.targetRefLevel;
     presentation.nEncodedTargetLevel = drc.encodedTargetLevel;
+    presentation.nPCMLimiterEnable = pcmLimiterEnable;
 
     status_t res = mOMX->setParameter(mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
     if (res == OK) {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index a72cbd5..c99db84 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -186,7 +186,8 @@
         const sp<IMediaHTTPService> &httpService,
         const char *uri,
         const KeyedVector<String8, String8> *headers,
-        String8 *contentType) {
+        String8 *contentType,
+        HTTPBase *httpSource) {
     if (contentType != NULL) {
         *contentType = "";
     }
@@ -204,14 +205,15 @@
             return NULL;
         }
 
-        sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
-        if (conn == NULL) {
-            ALOGE("Failed to make http connection from http service!");
-            return NULL;
+        if (httpSource == NULL) {
+            sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
+            if (conn == NULL) {
+                ALOGE("Failed to make http connection from http service!");
+                return NULL;
+            }
+            httpSource = new MediaHTTP(conn);
         }
 
-        sp<HTTPBase> httpSource = new MediaHTTP(conn);
-
         String8 tmp;
         if (isWidevine) {
             tmp = String8("http://");
@@ -264,6 +266,19 @@
     return source;
 }
 
+sp<DataSource> DataSource::CreateMediaHTTP(const sp<IMediaHTTPService> &httpService) {
+    if (httpService == NULL) {
+        return NULL;
+    }
+
+    sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
+    if (conn == NULL) {
+        return NULL;
+    } else {
+        return new MediaHTTP(conn);
+    }
+}
+
 String8 DataSource::getMIMEType() const {
     return String8("application/octet-stream");
 }
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index f469d4d..bd0a41d 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -456,6 +456,10 @@
     }
 
     Mutex::Autolock autoLock(mLock);
+    if (mDisconnecting) {
+        mCondition.signal();
+        return;
+    }
 
     CHECK(mAsyncResult == NULL);
 
@@ -502,6 +506,9 @@
     ALOGV("readAt offset %lld, size %zu", offset, size);
 
     Mutex::Autolock autoLock(mLock);
+    if (mDisconnecting) {
+        return ERROR_END_OF_STREAM;
+    }
 
     // If the request can be completely satisfied from the cache, do so.
 
@@ -528,6 +535,7 @@
     }
 
     if (mDisconnecting) {
+        mAsyncResult.clear();
         return ERROR_END_OF_STREAM;
     }
 
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index e701e9e..1b6eac4 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -368,6 +368,10 @@
                         aacPresParams->nEncodedTargetLevel);
                 updateDrcWrapper = true;
             }
+            if (aacPresParams->nPCMLimiterEnable >= 0) {
+                aacDecoder_SetParam(mAACDecoder, AAC_PCM_LIMITER_ENABLE,
+                        (aacPresParams->nPCMLimiterEnable != 0));
+            }
             if (updateDrcWrapper) {
                 mDrcWrap.update();
             }
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 7a9a1a3..fba6b09 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -494,6 +494,10 @@
                     AString uri;
                     CHECK(msg->findString("uri", &uri));
 
+                    if (mFetcherInfos.indexOfKey(uri) < 0) {
+                        ALOGE("couldn't find uri");
+                        break;
+                    }
                     FetcherInfo *info = &mFetcherInfos.editValueFor(uri);
                     info->mIsPrepared = true;
 
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 15f1f23..4678880 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -465,16 +465,21 @@
     if (status == 0) {
         status = cmdStatus;
     }
-    if (status == 0 &&
-            ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
-             (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC)) {
-        sp<ThreadBase> thread = mThread.promote();
-        if (thread != 0) {
-            audio_stream_t *stream = thread->stream();
-            if (stream != NULL) {
-                stream->add_audio_effect(stream, mEffectInterface);
+    if (status == 0) {
+        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
+             (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
+            sp<ThreadBase> thread = mThread.promote();
+            if (thread != 0) {
+                audio_stream_t *stream = thread->stream();
+                if (stream != NULL) {
+                    stream->add_audio_effect(stream, mEffectInterface);
+                }
             }
         }
+        sp<EffectChain> chain = mChain.promote();
+        if (chain != 0) {
+            chain->forceVolume();
+        }
     }
     return status;
 }
@@ -1326,7 +1331,7 @@
                                         int sessionId)
     : mThread(thread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
       mOwnInBuffer(false), mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
-      mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
+      mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX), mForceVolume(false)
 {
     mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
     if (thread == NULL) {
@@ -1649,7 +1654,8 @@
         }
     }
 
-    if (ctrlIdx == mVolumeCtrlIdx && *left == mLeftVolume && *right == mRightVolume) {
+    if (!isVolumeForced() && ctrlIdx == mVolumeCtrlIdx &&
+            *left == mLeftVolume && *right == mRightVolume) {
         if (hasControl) {
             *left = mNewLeftVolume;
             *right = mNewRightVolume;
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index eaf90e7..b87a1fd 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -318,6 +318,12 @@
     // At least one non offloadable effect in the chain is enabled
     bool isNonOffloadableEnabled();
 
+    // use release_cas because we don't care about the observed value, just want to make sure the
+    // new value is observable.
+    void forceVolume() { android_atomic_release_cas(false, true, &mForceVolume); }
+    // use acquire_cas because we are interested in the observed value and
+    // we are the only observers.
+    bool isVolumeForced() { return (android_atomic_acquire_cas(true, false, &mForceVolume) == 0); }
 
     void dump(int fd, const Vector<String16>& args);
 
@@ -375,4 +381,5 @@
     // timeLow fields among effect type UUIDs.
     // Updated by updateSuspendedSessions_l() only.
     KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
+    volatile int32_t mForceVolume; // force next volume command because a new effect was enabled
 };
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 66edf45..12e09ab 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2126,7 +2126,6 @@
             size_t totalFramesWritten = mNormalSink->framesWritten();
             if (totalFramesWritten >= mLatchD.mTimestamp.mPosition) {
                 mLatchD.mUnpresentedFrames = totalFramesWritten - mLatchD.mTimestamp.mPosition;
-                // mLatchD.mFramesReleased is set in threadloop_mix()
                 mLatchDValid = true;
             }
         }
@@ -3094,18 +3093,6 @@
     sleepTime = 0;
     standbyTime = systemTime() + standbyDelay;
     //TODO: delay standby when effects have a tail
-
-    mLatchD.mFramesReleased.clear();
-    {
-        Mutex::Autolock _l(mLock);
-        size_t size = mActiveTracks.size();
-        for (size_t i = 0; i < size; i++) {
-            sp<Track> t = mActiveTracks[i].promote();
-            if (t != 0) {
-                mLatchD.mFramesReleased.add(t.get(), t->mAudioTrackServerProxy->framesReleased());
-            }
-        }
-    }
 }
 
 void AudioFlinger::MixerThread::threadLoop_sleepTime()
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 7d3b854..7af5264 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -819,7 +819,6 @@
     struct {
         AudioTimestamp  mTimestamp;
         uint32_t        mUnpresentedFrames;
-        KeyedVector<Track *, uint32_t> mFramesReleased;
     } mLatchD, mLatchQ;
     bool mLatchDValid;  // true means mLatchD is valid, and clock it into latch at next opportunity
     bool mLatchQValid;  // true means mLatchQ is valid
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index b2d53cf..75190f3 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -898,15 +898,7 @@
         uint32_t unpresentedFrames =
                 ((int64_t) playbackThread->mLatchQ.mUnpresentedFrames * mSampleRate) /
                 playbackThread->mSampleRate;
-        // FIXME Since we're using a raw pointer as the key, it is theoretically possible
-        //       for a brand new track to share the same address as a recently destroyed
-        //       track, and thus for us to get the frames released of the wrong track.
-        //       It is unlikely that we would be able to call getTimestamp() so quickly
-        //       right after creating a new track.  Nevertheless, the index here should
-        //       be changed to something that is unique.  Or use a completely different strategy.
-        ssize_t i = playbackThread->mLatchQ.mFramesReleased.indexOfKey(this);
-        uint32_t framesWritten = i >= 0 ?
-                playbackThread->mLatchQ.mFramesReleased[i] : mAudioTrackServerProxy->framesReleased();
+        uint32_t framesWritten = mAudioTrackServerProxy->framesReleased();
         bool checkPreviousTimestamp = mPreviousValid && framesWritten >= mPreviousFramesWritten;
         if (framesWritten < unpresentedFrames) {
             mPreviousValid = false;