Merge "Buffer at least 2 secs worth of data at startup of after a seek before" into jb-dev
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index a94b16e..1dc408f 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -100,6 +100,7 @@
     bool mAllowDeepBuffering;       // allow audio deep audio buffers. Helps with low power audio
                                     // playback but implies high latency
     AwesomePlayer *mObserver;
+    int64_t mPinnedTimeUs;
 
     static void AudioCallback(int event, void *user, void *info);
     void AudioCallback(int event, void *info);
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index f729a78..6b1be1f 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -54,7 +54,8 @@
       mFirstBuffer(NULL),
       mAudioSink(audioSink),
       mAllowDeepBuffering(allowDeepBuffering),
-      mObserver(observer) {
+      mObserver(observer),
+      mPinnedTimeUs(-1ll) {
 }
 
 AudioPlayer::~AudioPlayer() {
@@ -141,9 +142,10 @@
                 mFirstBuffer = NULL;
             }
 
-            if (!sourceAlreadyStarted) {
-                mSource->stop();
-            }
+            // At this point, source already got started
+            // Stop the source when error is found.
+            mSource->stop();
+            mSource = NULL;
 
             return err;
         }
@@ -173,9 +175,9 @@
                 mFirstBuffer = NULL;
             }
 
-            if (!sourceAlreadyStarted) {
-                mSource->stop();
-            }
+            // At this point, source already got started
+            // Stop the source when error is found.
+            mSource->stop();
 
             return err;
         }
@@ -187,6 +189,7 @@
     }
 
     mStarted = true;
+    mPinnedTimeUs = -1ll;
 
     return OK;
 }
@@ -209,6 +212,8 @@
         } else {
             mAudioTrack->pause();
         }
+
+        mPinnedTimeUs = ALooper::GetNowUs();
     }
 }
 
@@ -490,6 +495,12 @@
         Mutex::Autolock autoLock(mLock);
         mNumFramesPlayed += size_done / mFrameSize;
         mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
+
+        if (mReachedEOS) {
+            mPinnedTimeUs = mNumFramesPlayedSysTimeUs;
+        } else {
+            mPinnedTimeUs = -1ll;
+        }
     }
 
     if (postEOS) {
@@ -516,7 +527,14 @@
     // Compensate for large audio buffers, updates of mNumFramesPlayed
     // are less frequent, therefore to get a "smoother" notion of time we
     // compensate using system time.
-    int64_t diffUs = ALooper::GetNowUs() - mNumFramesPlayedSysTimeUs;
+    int64_t diffUs;
+    if (mPinnedTimeUs >= 0ll) {
+        diffUs = mPinnedTimeUs;
+    } else {
+        diffUs = ALooper::GetNowUs();
+    }
+
+    diffUs -= mNumFramesPlayedSysTimeUs;
 
     return result + diffUs;
 }
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index b0d305b..4000686 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -177,11 +177,11 @@
             } else {
                 pcmParams->nChannels = mStreamInfo->numChannels;
                 pcmParams->nSamplingRate = mStreamInfo->sampleRate;
+                ALOGI("Sampling rate: %lu, channels: %lu",
+                      pcmParams->nSamplingRate,
+                      pcmParams->nChannels);
             }
 
-            if (!pcmParams->nChannels) ALOGW("Audio contains 0 channels");
-            if (!pcmParams->nSamplingRate) ALOGW("Sampling rate of 0 Hz");
-
             return OMX_ErrorNone;
         }
 
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
index 24c2f30..f9a44f0 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
@@ -534,27 +534,7 @@
     LOG(VERBOSE) << "Access unit complete (" << mPackets.size() << " packets)";
 #endif
 
-    size_t totalSize = 0;
-    List<sp<ABuffer> >::iterator it = mPackets.begin();
-    while (it != mPackets.end()) {
-        const sp<ABuffer> &unit = *it;
-
-        totalSize += unit->size();
-        ++it;
-    }
-
-    sp<ABuffer> accessUnit = new ABuffer(totalSize);
-    size_t offset = 0;
-    it = mPackets.begin();
-    while (it != mPackets.end()) {
-        const sp<ABuffer> &unit = *it;
-
-        memcpy((uint8_t *)accessUnit->data() + offset,
-               unit->data(), unit->size());
-
-        ++it;
-    }
-
+    sp<ABuffer> accessUnit = MakeCompoundFromPackets(mPackets);
     accessUnit = removeLATMFraming(accessUnit);
     CopyTimes(accessUnit, *mPackets.begin());
 
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
index 687d72b..eefceba 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
@@ -21,6 +21,7 @@
 #include "AMPEG4ElementaryAssembler.h"
 
 #include "ARTPSource.h"
+#include "ASessionDescription.h"
 
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -85,6 +86,25 @@
     return true;
 }
 
+static bool GetSampleRateIndex(int32_t sampleRate, size_t *tableIndex) {
+    static const int32_t kSampleRateTable[] = {
+        96000, 88200, 64000, 48000, 44100, 32000,
+        24000, 22050, 16000, 12000, 11025, 8000
+    };
+    const size_t kNumSampleRates =
+        sizeof(kSampleRateTable) / sizeof(kSampleRateTable[0]);
+
+    *tableIndex = 0;
+    for (size_t index = 0; index < kNumSampleRates; ++index) {
+        if (sampleRate == kSampleRateTable[index]) {
+            *tableIndex = index;
+            return true;
+        }
+    }
+
+    return false;
+}
+
 // static
 AMPEG4ElementaryAssembler::AMPEG4ElementaryAssembler(
         const sp<AMessage> &notify, const AString &desc, const AString &params)
@@ -100,6 +120,8 @@
       mStreamStateIndication(0),
       mAuxiliaryDataSizeLength(0),
       mHasAUHeader(false),
+      mChannelConfig(0),
+      mSampleRateIndex(0),
       mAccessUnitRTPTime(0),
       mNextExpectedSeqNoValid(false),
       mNextExpectedSeqNo(0),
@@ -163,6 +185,13 @@
             || mDTSDeltaLength > 0
             || mRandomAccessIndication
             || mStreamStateIndication > 0;
+
+        int32_t sampleRate, numChannels;
+        ASessionDescription::ParseFormatDesc(
+                desc.c_str(), &sampleRate, &numChannels);
+
+        mChannelConfig = numChannels;
+        CHECK(GetSampleRateIndex(sampleRate, &mSampleRateIndex));
     }
 }
 
@@ -338,23 +367,18 @@
 
     ALOGV("Access unit complete (%d nal units)", mPackets.size());
 
-    size_t totalSize = 0;
-    for (List<sp<ABuffer> >::iterator it = mPackets.begin();
-         it != mPackets.end(); ++it) {
-        totalSize += (*it)->size();
-    }
+    sp<ABuffer> accessUnit;
 
-    sp<ABuffer> accessUnit = new ABuffer(totalSize);
-    size_t offset = 0;
-    for (List<sp<ABuffer> >::iterator it = mPackets.begin();
-         it != mPackets.end(); ++it) {
-        sp<ABuffer> nal = *it;
-        memcpy(accessUnit->data() + offset, nal->data(), nal->size());
-        offset += nal->size();
+    if (mIsGeneric) {
+        accessUnit = MakeADTSCompoundFromAACFrames(
+                OMX_AUDIO_AACObjectLC - 1,
+                mSampleRateIndex,
+                mChannelConfig,
+                mPackets);
+    } else {
+        accessUnit = MakeCompoundFromPackets(mPackets);
     }
 
-    CopyTimes(accessUnit, *mPackets.begin());
-
 #if 0
     printf(mAccessUnitDamaged ? "X" : ".");
     fflush(stdout);
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
index 794bbcc..693fca5 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
@@ -25,6 +25,8 @@
 #include <utils/List.h>
 #include <utils/RefBase.h>
 
+#include <OMX_Audio.h>
+
 namespace android {
 
 struct ABuffer;
@@ -57,6 +59,9 @@
     unsigned mAuxiliaryDataSizeLength;
     bool mHasAUHeader;
 
+    int32_t mChannelConfig;
+    size_t mSampleRateIndex;
+
     uint32_t mAccessUnitRTPTime;
     bool mNextExpectedSeqNoValid;
     uint32_t mNextExpectedSeqNo;
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 6cf1301..fc177d2 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -551,6 +551,7 @@
 
         mFormat->setInt32(kKeySampleRate, sampleRate);
         mFormat->setInt32(kKeyChannelCount, numChannels);
+        mFormat->setInt32(kKeyIsADTS, true);
 
         sp<ABuffer> codecSpecificData =
             MakeAACCodecSpecificData2(params.c_str());
diff --git a/media/libstagefright/rtsp/ARTPAssembler.cpp b/media/libstagefright/rtsp/ARTPAssembler.cpp
index a897c10..1844bc5 100644
--- a/media/libstagefright/rtsp/ARTPAssembler.cpp
+++ b/media/libstagefright/rtsp/ARTPAssembler.cpp
@@ -74,4 +74,77 @@
     to->setInt32Data(from->int32Data());
 }
 
+// static
+sp<ABuffer> ARTPAssembler::MakeADTSCompoundFromAACFrames(
+        unsigned profile,
+        unsigned samplingFreqIndex,
+        unsigned channelConfig,
+        const List<sp<ABuffer> > &frames) {
+    size_t totalSize = 0;
+    for (List<sp<ABuffer> >::const_iterator it = frames.begin();
+         it != frames.end(); ++it) {
+        // Each frame is prefixed by a 7 byte ADTS header
+        totalSize += (*it)->size() + 7;
+    }
+
+    sp<ABuffer> accessUnit = new ABuffer(totalSize);
+    size_t offset = 0;
+    for (List<sp<ABuffer> >::const_iterator it = frames.begin();
+         it != frames.end(); ++it) {
+        sp<ABuffer> nal = *it;
+        uint8_t *dst = accessUnit->data() + offset;
+
+        static const unsigned kADTSId = 0;
+        static const unsigned kADTSLayer = 0;
+        static const unsigned kADTSProtectionAbsent = 1;
+
+        unsigned frameLength = nal->size() + 7;
+
+        dst[0] = 0xff;
+
+        dst[1] =
+            0xf0 | (kADTSId << 3) | (kADTSLayer << 1) | kADTSProtectionAbsent;
+
+        dst[2] = (profile << 6)
+                | (samplingFreqIndex << 2)
+                | (channelConfig >> 2);
+
+        dst[3] = ((channelConfig & 3) << 6) | (frameLength >> 11);
+
+        dst[4] = (frameLength >> 3) & 0xff;
+        dst[5] = (frameLength & 7) << 5;
+        dst[6] = 0x00;
+
+        memcpy(dst + 7, nal->data(), nal->size());
+        offset += nal->size() + 7;
+    }
+
+    CopyTimes(accessUnit, *frames.begin());
+
+    return accessUnit;
+}
+
+// static
+sp<ABuffer> ARTPAssembler::MakeCompoundFromPackets(
+        const List<sp<ABuffer> > &packets) {
+    size_t totalSize = 0;
+    for (List<sp<ABuffer> >::const_iterator it = packets.begin();
+         it != packets.end(); ++it) {
+        totalSize += (*it)->size();
+    }
+
+    sp<ABuffer> accessUnit = new ABuffer(totalSize);
+    size_t offset = 0;
+    for (List<sp<ABuffer> >::const_iterator it = packets.begin();
+         it != packets.end(); ++it) {
+        sp<ABuffer> nal = *it;
+        memcpy(accessUnit->data() + offset, nal->data(), nal->size());
+        offset += nal->size();
+    }
+
+    CopyTimes(accessUnit, *packets.begin());
+
+    return accessUnit;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/rtsp/ARTPAssembler.h b/media/libstagefright/rtsp/ARTPAssembler.h
index 70ea186..7c147be 100644
--- a/media/libstagefright/rtsp/ARTPAssembler.h
+++ b/media/libstagefright/rtsp/ARTPAssembler.h
@@ -19,6 +19,7 @@
 #define A_RTP_ASSEMBLER_H_
 
 #include <media/stagefright/foundation/ABase.h>
+#include <utils/List.h>
 #include <utils/RefBase.h>
 
 namespace android {
@@ -45,6 +46,15 @@
 
     static void CopyTimes(const sp<ABuffer> &to, const sp<ABuffer> &from);
 
+    static sp<ABuffer> MakeADTSCompoundFromAACFrames(
+            unsigned profile,
+            unsigned samplingFreqIndex,
+            unsigned channelConfig,
+            const List<sp<ABuffer> > &frames);
+
+    static sp<ABuffer> MakeCompoundFromPackets(
+            const List<sp<ABuffer> > &frames);
+
 private:
     int64_t mFirstFailureTimeUs;