Merge "Bug 7170947 Configure AAC decoder for mobile DRC settings" into jb-mr1-dev
diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp
index 60cca69..6f336c7 100644
--- a/media/libstagefright/wifi-display/source/Converter.cpp
+++ b/media/libstagefright/wifi-display/source/Converter.cpp
@@ -44,7 +44,12 @@
       mCodecLooper(codecLooper),
       mInputFormat(format),
       mIsVideo(false),
-      mDoMoreWorkPending(false) {
+      mDoMoreWorkPending(false)
+#if ENABLE_SILENCE_DETECTION
+      ,mFirstSilentFrameUs(-1ll)
+      ,mInSilentMode(false)
+#endif
+    {
     AString mime;
     CHECK(mInputFormat->findString("mime", &mime));
 
@@ -132,9 +137,9 @@
         mOutputFormat->setInt32("bitrate", audioBitrate);
     } else {
         mOutputFormat->setInt32("bitrate", videoBitrate);
-        mOutputFormat->setInt32("frame-rate", 60);
+        mOutputFormat->setInt32("frame-rate", 30);
         mOutputFormat->setInt32("i-frame-interval", 1);  // Iframes every 1 secs
-        // mOutputFormat->setInt32("prepend-sps-pps-to-idr-frames", 1);
+        mOutputFormat->setInt32("prepend-sps-pps-to-idr-frames", 1);
     }
 
     ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str());
@@ -171,6 +176,20 @@
     notify->post();
 }
 
+// static
+bool Converter::IsSilence(const sp<ABuffer> &accessUnit) {
+    const uint8_t *ptr = accessUnit->data();
+    const uint8_t *end = ptr + accessUnit->size();
+    while (ptr < end) {
+        if (*ptr != 0) {
+            return false;
+        }
+        ++ptr;
+    }
+
+    return true;
+}
+
 void Converter::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatMediaPullerNotify:
@@ -220,6 +239,30 @@
                 }
 #endif
 
+#if ENABLE_SILENCE_DETECTION
+                if (!mIsVideo) {
+                    if (IsSilence(accessUnit)) {
+                        if (!mInSilentMode) {
+                            int64_t nowUs = ALooper::GetNowUs();
+
+                            if (mFirstSilentFrameUs < 0ll) {
+                                mFirstSilentFrameUs = nowUs;
+                            } else if (nowUs >= mFirstSilentFrameUs + 1000000ll) {
+                                mInSilentMode = true;
+                                ALOGI("audio in silent mode now.");
+                                break;
+                            }
+                        }
+                    } else {
+                        if (mInSilentMode) {
+                            ALOGI("audio no longer in silent mode.");
+                        }
+                        mInSilentMode = false;
+                        mFirstSilentFrameUs = -1ll;
+                    }
+                }
+#endif
+
                 mInputBufferQueue.push_back(accessUnit);
 
                 feedEncoderInputBuffers();
@@ -283,7 +326,7 @@
     }
 
     mDoMoreWorkPending = true;
-    (new AMessage(kWhatDoMoreWork, id()))->post(1000ll);
+    (new AMessage(kWhatDoMoreWork, id()))->post(mIsVideo ? 10000ll : 5000ll);
 }
 
 status_t Converter::feedEncoderInputBuffers() {
@@ -338,14 +381,21 @@
         feedEncoderInputBuffers();
     }
 
-    size_t offset;
-    size_t size;
-    int64_t timeUs;
-    uint32_t flags;
-    err = mEncoder->dequeueOutputBuffer(
-            &bufferIndex, &offset, &size, &timeUs, &flags);
+    for (;;) {
+        size_t offset;
+        size_t size;
+        int64_t timeUs;
+        uint32_t flags;
+        err = mEncoder->dequeueOutputBuffer(
+                &bufferIndex, &offset, &size, &timeUs, &flags);
 
-    if (err == OK) {
+        if (err != OK) {
+            if (err == -EAGAIN) {
+                err = OK;
+            }
+            break;
+        }
+
         if (flags & MediaCodec::BUFFER_FLAG_EOS) {
             sp<AMessage> notify = mNotify->dup();
             notify->setInt32("what", kWhatEOS);
@@ -354,6 +404,10 @@
             sp<ABuffer> buffer = new ABuffer(size);
             buffer->meta()->setInt64("timeUs", timeUs);
 
+            if (!mIsVideo) {
+                ALOGV("audio time %lld us (%.2f secs)", timeUs, timeUs / 1E6);
+            }
+
             memcpy(buffer->data(),
                    mEncoderOutputBuffers.itemAt(bufferIndex)->base() + offset,
                    size);
@@ -368,9 +422,11 @@
             }
         }
 
-        err = mEncoder->releaseOutputBuffer(bufferIndex);
-    } else if (err == -EAGAIN) {
-        err = OK;
+        mEncoder->releaseOutputBuffer(bufferIndex);
+
+        if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+            break;
+        }
     }
 
     return err;
diff --git a/media/libstagefright/wifi-display/source/Converter.h b/media/libstagefright/wifi-display/source/Converter.h
index 9f54523..93ff72f 100644
--- a/media/libstagefright/wifi-display/source/Converter.h
+++ b/media/libstagefright/wifi-display/source/Converter.h
@@ -25,6 +25,8 @@
 struct ABuffer;
 struct MediaCodec;
 
+#define ENABLE_SILENCE_DETECTION        1
+
 // Utility class that receives media access units and converts them into
 // media access unit of a different format.
 // Right now this'll convert raw video into H.264 and raw audio into AAC.
@@ -83,6 +85,11 @@
 
     bool mDoMoreWorkPending;
 
+#if ENABLE_SILENCE_DETECTION
+    int64_t mFirstSilentFrameUs;
+    bool mInSilentMode;
+#endif
+
     status_t initEncoder();
 
     status_t feedEncoderInputBuffers();
@@ -92,6 +99,8 @@
 
     void notifyError(status_t err);
 
+    static bool IsSilence(const sp<ABuffer> &accessUnit);
+
     DISALLOW_EVIL_CONSTRUCTORS(Converter);
 };
 
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index 7de607c..c91b4c8 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -64,6 +64,8 @@
           const sp<MediaPuller> &mediaPuller,
           const sp<Converter> &converter);
 
+    void setRepeaterSource(const sp<RepeaterSource> &source);
+
     sp<AMessage> getFormat();
     bool isAudio() const;
 
@@ -78,6 +80,8 @@
     void queueAccessUnit(const sp<ABuffer> &accessUnit);
     sp<ABuffer> dequeueAccessUnit();
 
+    void requestIDRFrame();
+
 protected:
     virtual void onMessageReceived(const sp<AMessage> &msg);
     virtual ~Track();
@@ -96,6 +100,7 @@
     ssize_t mPacketizerTrackIndex;
     bool mIsAudio;
     List<sp<ABuffer> > mQueuedAccessUnits;
+    sp<RepeaterSource> mRepeaterSource;
 
     static bool IsAudioFormat(const sp<AMessage> &format);
 
@@ -178,6 +183,11 @@
     sp<AMessage> msg = new AMessage(kWhatMediaPullerStopped, id());
 
     if (mStarted && mMediaPuller != NULL) {
+        if (mRepeaterSource != NULL) {
+            // Let's unblock MediaPuller's MediaSource::read().
+            mRepeaterSource->wakeUp();
+        }
+
         mMediaPuller->stopAsync(msg);
     } else {
         msg->post();
@@ -224,6 +234,23 @@
     return accessUnit;
 }
 
+void WifiDisplaySource::PlaybackSession::Track::setRepeaterSource(
+        const sp<RepeaterSource> &source) {
+    mRepeaterSource = source;
+}
+
+void WifiDisplaySource::PlaybackSession::Track::requestIDRFrame() {
+    if (mIsAudio) {
+        return;
+    }
+
+    if (mRepeaterSource != NULL) {
+        mRepeaterSource->wakeUp();
+    }
+
+    mConverter->requestIDRFrame();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 WifiDisplaySource::PlaybackSession::PlaybackSession(
@@ -264,8 +291,10 @@
       mNumRTPSent(0),
       mNumRTPOctetsSent(0),
       mNumSRsSent(0),
-      mSendSRPending(false),
-      mHistoryLength(0)
+      mSendSRPending(false)
+#if ENABLE_RETRANSMISSION
+      ,mHistoryLength(0)
+#endif
 #if TRACK_BANDWIDTH
       ,mFirstPacketTimeUs(-1ll)
       ,mTotalBytesSent(0ll)
@@ -807,7 +836,8 @@
 }
 
 status_t WifiDisplaySource::PlaybackSession::addSource(
-        bool isVideo, const sp<MediaSource> &source, size_t *numInputBuffers) {
+        bool isVideo, const sp<MediaSource> &source, bool isRepeaterSource,
+        size_t *numInputBuffers) {
     sp<ALooper> pullLooper = new ALooper;
     pullLooper->setName("pull_looper");
 
@@ -869,6 +899,10 @@
     sp<Track> track = new Track(
             notify, pullLooper, codecLooper, puller, converter);
 
+    if (isRepeaterSource) {
+        track->setRepeaterSource(static_cast<RepeaterSource *>(source.get()));
+    }
+
     looper()->registerHandler(track);
 
     mTracks.add(trackIndex, track);
@@ -885,8 +919,13 @@
 
     source->setUseAbsoluteTimestamps();
 
+    sp<RepeaterSource> videoSource =
+        new RepeaterSource(source, 30.0 /* rateHz */);
+
     size_t numInputBuffers;
-    status_t err = addSource(true /* isVideo */, source, &numInputBuffers);
+    status_t err = addSource(
+            true /* isVideo */, videoSource, true /* isRepeaterSource */,
+            &numInputBuffers);
 
     if (err != OK) {
         return err;
@@ -908,7 +947,8 @@
 
     if (audioSource->initCheck() == OK) {
         return addSource(
-                false /* isVideo */, audioSource, NULL /* numInputBuffers */);
+                false /* isVideo */, audioSource, false /* isRepeaterSource */,
+                NULL /* numInputBuffers */);
     }
 
     ALOGW("Unable to instantiate audio source");
@@ -1126,7 +1166,9 @@
 #endif
         }
 
+#if ENABLE_RETRANSMISSION
         mTSQueue->setInt32Data(mRTPSeqNo - 1);
+
         mHistory.push_back(mTSQueue);
         ++mHistoryLength;
 
@@ -1138,6 +1180,7 @@
         } else {
             mTSQueue = new ABuffer(12 + kMaxNumTSPacketsPerRTPPacket * 188);
         }
+#endif
 
         mTSQueue->setRange(0, 12);
     }
@@ -1295,7 +1338,7 @@
     for (size_t i = 0; i < mTracks.size(); ++i) {
         const sp<Track> &track = mTracks.valueAt(i);
 
-        track->converter()->requestIDRFrame();
+        track->requestIDRFrame();
     }
 }
 
@@ -1321,7 +1364,7 @@
 }
 
 status_t WifiDisplaySource::PlaybackSession::packetizeAccessUnit(
-        size_t trackIndex, sp<ABuffer> accessUnit) {
+        size_t trackIndex, const sp<ABuffer> &accessUnit) {
     const sp<Track> &track = mTracks.valueFor(trackIndex);
 
     uint32_t flags = 0;
@@ -1332,12 +1375,6 @@
     if (mHDCP != NULL && !track->isAudio()) {
         isHDCPEncrypted = true;
 
-        if (IsIDR(accessUnit)) {
-            // XXX remove this once the encoder takes care of this.
-            accessUnit = mPacketizer->prependCSD(
-                    track->packetizerTrackIndex(), accessUnit);
-        }
-
         status_t err = mHDCP->encrypt(
                 accessUnit->data(), accessUnit->size(),
                 trackIndex  /* streamCTR */,
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.h b/media/libstagefright/wifi-display/source/PlaybackSession.h
index 8d88648..5d4bde8 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.h
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.h
@@ -161,8 +161,10 @@
 
     bool mSendSRPending;
 
+#if ENABLE_RETRANSMISSION
     List<sp<ABuffer> > mHistory;
     size_t mHistoryLength;
+#endif
 
 #if TRACK_BANDWIDTH
     int64_t mFirstPacketTimeUs;
@@ -183,6 +185,7 @@
     status_t addSource(
             bool isVideo,
             const sp<MediaSource> &source,
+            bool isRepeaterSource,
             size_t *numInputBuffers);
 
     status_t addVideoSource();
@@ -206,7 +209,7 @@
     bool allTracksHavePacketizerIndex();
 
     status_t packetizeAccessUnit(
-            size_t trackIndex, sp<ABuffer> accessUnit);
+            size_t trackIndex, const sp<ABuffer> &accessUnit);
 
     status_t packetizeQueuedAccessUnits();
 
diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.cpp b/media/libstagefright/wifi-display/source/RepeaterSource.cpp
index dc216e8..641e63f 100644
--- a/media/libstagefright/wifi-display/source/RepeaterSource.cpp
+++ b/media/libstagefright/wifi-display/source/RepeaterSource.cpp
@@ -18,6 +18,7 @@
       mRateHz(rateHz),
       mBuffer(NULL),
       mResult(OK),
+      mLastBufferUpdateUs(-1ll),
       mStartTimeUs(-1ll),
       mFrameCount(0) {
 }
@@ -91,39 +92,60 @@
     ReadOptions::SeekMode seekMode;
     CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &seekMode));
 
-    int64_t bufferTimeUs = -1ll;
+    for (;;) {
+        int64_t bufferTimeUs = -1ll;
 
-    if (mStartTimeUs < 0ll) {
-        Mutex::Autolock autoLock(mLock);
-        while (mBuffer == NULL && mResult == OK) {
-            mCondition.wait(mLock);
+        if (mStartTimeUs < 0ll) {
+            Mutex::Autolock autoLock(mLock);
+            while ((mLastBufferUpdateUs < 0ll || mBuffer == NULL)
+                    && mResult == OK) {
+                mCondition.wait(mLock);
+            }
+
+            ALOGV("now resuming.");
+            mStartTimeUs = ALooper::GetNowUs();
+            bufferTimeUs = mStartTimeUs;
+        } else {
+            bufferTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz;
+
+            int64_t nowUs = ALooper::GetNowUs();
+            int64_t delayUs = bufferTimeUs - nowUs;
+
+            if (delayUs > 0ll) {
+                usleep(delayUs);
+            }
         }
 
-        mStartTimeUs = ALooper::GetNowUs();
-        bufferTimeUs = mStartTimeUs;
-    } else {
-        bufferTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz;
+        bool stale = false;
 
-        int64_t nowUs = ALooper::GetNowUs();
-        int64_t delayUs = bufferTimeUs - nowUs;
+        {
+            Mutex::Autolock autoLock(mLock);
+            if (mResult != OK) {
+                CHECK(mBuffer == NULL);
+                return mResult;
+            }
 
-        if (delayUs > 0ll) {
-            usleep(delayUs);
+            int64_t nowUs = ALooper::GetNowUs();
+            if (nowUs - mLastBufferUpdateUs > 1000000ll) {
+                mLastBufferUpdateUs = -1ll;
+                stale = true;
+            } else {
+                mBuffer->add_ref();
+                *buffer = mBuffer;
+                (*buffer)->meta_data()->setInt64(kKeyTime, bufferTimeUs);
+                ++mFrameCount;
+            }
         }
+
+        if (!stale) {
+            break;
+        }
+
+        mStartTimeUs = -1ll;
+        mFrameCount = 0;
+        ALOGV("now dormant");
     }
 
-    Mutex::Autolock autoLock(mLock);
-    if (mResult != OK) {
-        CHECK(mBuffer == NULL);
-        return mResult;
-    }
-
-    mBuffer->add_ref();
-    *buffer = mBuffer;
-    (*buffer)->meta_data()->setInt64(kKeyTime, bufferTimeUs);
-
-    ++mFrameCount;
-
     return OK;
 }
 
@@ -147,6 +169,7 @@
             }
             mBuffer = buffer;
             mResult = err;
+            mLastBufferUpdateUs = ALooper::GetNowUs();
 
             mCondition.broadcast();
 
@@ -161,4 +184,13 @@
     }
 }
 
+void RepeaterSource::wakeUp() {
+    ALOGV("wakeUp");
+    Mutex::Autolock autoLock(mLock);
+    if (mLastBufferUpdateUs < 0ll && mBuffer != NULL) {
+        mLastBufferUpdateUs = ALooper::GetNowUs();
+        mCondition.broadcast();
+    }
+}
+
 }  // namespace android
diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.h b/media/libstagefright/wifi-display/source/RepeaterSource.h
index 3049362..e4aa2b6 100644
--- a/media/libstagefright/wifi-display/source/RepeaterSource.h
+++ b/media/libstagefright/wifi-display/source/RepeaterSource.h
@@ -22,6 +22,10 @@
 
     void onMessageReceived(const sp<AMessage> &msg);
 
+    // If RepeaterSource is currently dormant, because SurfaceFlinger didn't
+    // send updates in a while, this is its wakeup call.
+    void wakeUp();
+
 protected:
     virtual ~RepeaterSource();
 
@@ -43,6 +47,7 @@
 
     MediaBuffer *mBuffer;
     status_t mResult;
+    int64_t mLastBufferUpdateUs;
 
     int64_t mStartTimeUs;
     int32_t mFrameCount;
diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.cpp b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
index dd18998..e5abd57 100644
--- a/media/libstagefright/wifi-display/source/TSPacketizer.cpp
+++ b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
@@ -294,12 +294,11 @@
 
     const sp<Track> &track = mTracks.itemAt(trackIndex);
 
-    if (track->isH264() && !(flags & IS_ENCRYPTED)) {
-        if (IsIDR(accessUnit)) {
-            // prepend codec specific data, i.e. SPS and PPS.
-            accessUnit = track->prependCSD(accessUnit);
-        }
-    } else if (track->lacksADTSHeader()) {
+    if (track->isH264() && (flags & PREPEND_SPS_PPS_TO_IDR_FRAMES)
+            && IsIDR(accessUnit)) {
+        // prepend codec specific data, i.e. SPS and PPS.
+        accessUnit = track->prependCSD(accessUnit);
+    } else if (track->isAudio() && track->lacksADTSHeader()) {
         CHECK(!(flags & IS_ENCRYPTED));
         accessUnit = track->prependADTSHeader(accessUnit);
     }
diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.h b/media/libstagefright/wifi-display/source/TSPacketizer.h
index 01f174a..0733c06 100644
--- a/media/libstagefright/wifi-display/source/TSPacketizer.h
+++ b/media/libstagefright/wifi-display/source/TSPacketizer.h
@@ -38,9 +38,10 @@
     ssize_t addTrack(const sp<AMessage> &format);
 
     enum {
-        EMIT_PAT_AND_PMT = 1,
-        EMIT_PCR         = 2,
-        IS_ENCRYPTED     = 4,
+        EMIT_PAT_AND_PMT                = 1,
+        EMIT_PCR                        = 2,
+        IS_ENCRYPTED                    = 4,
+        PREPEND_SPS_PPS_TO_IDR_FRAMES   = 8,
     };
     status_t packetize(
             size_t trackIndex, const sp<ABuffer> &accessUnit,
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 1083a80..b0aaf3b 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -539,7 +539,7 @@
     //   use "78 00 02 02 00008000 00000000 00000000 00 0000 0000 00 none none\r\n"
     AString body = StringPrintf(
         "wfd_video_formats: "
-        "30 00 02 02 00000040 00000000 00000000 00 0000 0000 00 none none\r\n"
+        "28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none\r\n"
         "wfd_audio_codecs: AAC 00000001 00\r\n"  // 2 ch AAC 48kHz
         "wfd_presentation_URL: rtsp://%s/wfd1.0/streamid=0 none\r\n"
         "wfd_client_rtp_ports: RTP/AVP/%s;unicast 19000 0 mode=play\r\n",