Merge "Support for auxiliary video parameters."
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 5a87f4c..c424281 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -32,9 +32,15 @@
 
 using namespace android;
 
+static const int32_t kFramerate = 24;  // fps
+static const int32_t kIFramesIntervalSec = 1;
+static const int32_t kVideoBitRate = 512 * 1024;
+static const int32_t kAudioBitRate = 12200;
+static const int32_t kColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+static const int64_t kDurationUs = 10000000LL;  // 10 seconds
+
 #if 1
 class DummySource : public MediaSource {
-    static const int32_t kFramerate = 24;  // fps
 
 public:
     DummySource(int width, int height)
@@ -176,6 +182,12 @@
     enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
     enc_meta->setInt32(kKeyWidth, width);
     enc_meta->setInt32(kKeyHeight, height);
+    enc_meta->setInt32(kKeySampleRate, kFramerate);
+    enc_meta->setInt32(kKeyBitRate, kVideoBitRate);
+    enc_meta->setInt32(kKeyStride, width);
+    enc_meta->setInt32(kKeySliceHeight, height);
+    enc_meta->setInt32(kKeyIFramesInterval, kIFramesIntervalSec);
+    enc_meta->setInt32(kKeyColorFormat, kColorFormat);
 
     sp<MediaSource> encoder =
         OMXCodec::Create(
@@ -184,8 +196,10 @@
 #if 1
     sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
     writer->addSource(encoder);
+    writer->setMaxFileDuration(kDurationUs);
     writer->start();
     while (!writer->reachedEOS()) {
+        fprintf(stderr, ".");
         usleep(100000);
     }
     writer->stop();
@@ -194,6 +208,8 @@
 
     MediaBuffer *buffer;
     while (encoder->read(&buffer) == OK) {
+        printf(".");
+        fflush(stdout);
         int32_t isSync;
         if (!buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isSync)) {
             isSync = false;
@@ -209,6 +225,7 @@
     encoder->stop();
 #endif
 
+    printf("$\n");
     client.disconnect();
 #endif
 
@@ -267,6 +284,7 @@
     encMeta->setInt32(kKeySampleRate, kSampleRate);
     encMeta->setInt32(kKeyChannelCount, kNumChannels);
     encMeta->setInt32(kKeyMaxInputSize, 8192);
+    encMeta->setInt32(kKeyBitRate, kAudioBitRate);
 
     sp<MediaSource> encoder =
         OMXCodec::Create(client.interface(), encMeta, true, audioSource);
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index d3bb96e..7297811 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -258,16 +258,24 @@
         pContext->pBundledContext->firstVolume              = LVM_TRUE;
 
         #ifdef LVM_PCM
-        pContext->pBundledContext->PcmInPtr  = NULL;
-        pContext->pBundledContext->PcmOutPtr = NULL;
 
-        pContext->pBundledContext->PcmInPtr  = fopen("/data/tmp/bundle_pcm_in.pcm", "w");
-        pContext->pBundledContext->PcmOutPtr = fopen("/data/tmp/bundle_pcm_out.pcm", "w");
-
-        if((pContext->pBundledContext->PcmInPtr  == NULL)||
-           (pContext->pBundledContext->PcmOutPtr == NULL)){
+        char fileName[256];
+        snprintf(fileName, 256, "/data/tmp/bundle_%p_pcm_in.pcm", pContext->pBundledContext);
+        pContext->pBundledContext->PcmInPtr = fopen(fileName, "w");
+        if (pContext->pBundledContext->PcmInPtr == NULL) {
+            LOGV("cannot open %s", fileName);
            return -EINVAL;
         }
+
+        snprintf(fileName, 256, "/data/tmp/bundle_%p_pcm_out.pcm", pContext->pBundledContext);
+        pContext->pBundledContext->PcmOutPtr = fopen(fileName, "w");
+        if (pContext->pBundledContext->PcmOutPtr == NULL) {
+            LOGV("cannot open %s", fileName);
+            fclose(pContext->pBundledContext->PcmInPtr);
+           pContext->pBundledContext->PcmInPtr = NULL;
+           return -EINVAL;
+        }
+
         #endif
 
         /* Saved strength is used to return the exact strength that was used in the set to the get
@@ -375,8 +383,14 @@
     (GlobalSessionMemory[pContext->pBundledContext->SessionNo].bVirtualizerInstantiated==LVM_FALSE))
     {
         #ifdef LVM_PCM
-        fclose(pContext->pBundledContext->PcmInPtr);
-        fclose(pContext->pBundledContext->PcmOutPtr);
+        if (pContext->pBundledContext->PcmInPtr != NULL) {
+            fclose(pContext->pBundledContext->PcmInPtr);
+            pContext->pBundledContext->PcmInPtr = NULL;
+        }
+        if (pContext->pBundledContext->PcmOutPtr != NULL) {
+            fclose(pContext->pBundledContext->PcmOutPtr);
+            pContext->pBundledContext->PcmOutPtr = NULL;
+        }
         #endif
 
         LvmSessionsActive--;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 085e92d..183874c 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -274,9 +274,13 @@
 status_t AwesomePlayer::setDataSource(
         int fd, int64_t offset, int64_t length) {
 #if 0
+    // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/sl.m3u8");
+    return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/0440.m3u8");
+    // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/0640.m3u8");
+    // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/1240_vod.m3u8");
     // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_96.m3u8");
     // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_1500.m3u8");
-    return setDataSource("httplive://iphone.video.hsn.com/iPhone_high.m3u8");
+    // return setDataSource("httplive://iphone.video.hsn.com/iPhone_high.m3u8");
     // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/iphonewebcast/webcast090209_all/webcast090209_all.m3u8");
     // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_062209_iphone/hi/prog_index.m3u8");
     // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_googmaps/hi/prog_index.m3u8");
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 26a0fb3..72de8d7 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -78,6 +78,8 @@
             unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS,
             const uint8_t *data, size_t size);
 
+    void extractAACFrames(const sp<ABuffer> &buffer);
+
     DISALLOW_EVIL_CONSTRUCTORS(Stream);
 };
 
@@ -226,7 +228,7 @@
 ATSParser::Stream::Stream(unsigned elementaryPID, unsigned streamType)
     : mElementaryPID(elementaryPID),
       mStreamType(streamType),
-      mBuffer(new ABuffer(65536)),
+      mBuffer(new ABuffer(128 * 1024)),
       mPayloadStarted(false) {
     mBuffer->setRange(0, 0);
 }
@@ -662,7 +664,7 @@
     csd->data()[sizeof(kStaticESDS) + 1] =
         ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
 
-    hexdump(csd->data(), csd->size());
+    // hexdump(csd->data(), csd->size());
     return csd;
 }
 
@@ -727,13 +729,76 @@
     buffer->meta()->setInt64("time", (PTS * 100) / 9);
 
     if (mStreamType == 0x0f) {
-        // WHY???
-        buffer->setRange(7, buffer->size() - 7);
+        extractAACFrames(buffer);
     }
 
     mSource->queueAccessUnit(buffer);
 }
 
+// Disassemble one or more ADTS frames into their constituent parts and
+// leave only the concatenated raw_data_blocks in the buffer.
+void ATSParser::Stream::extractAACFrames(const sp<ABuffer> &buffer) {
+    size_t dstOffset = 0;
+
+    size_t offset = 0;
+    while (offset < buffer->size()) {
+        CHECK_LE(offset + 7, buffer->size());
+
+        ABitReader bits(buffer->data() + offset, buffer->size() - offset);
+
+        // adts_fixed_header
+
+        CHECK_EQ(bits.getBits(12), 0xfffu);
+        bits.skipBits(3);  // ID, layer
+        bool protection_absent = bits.getBits(1) != 0;
+
+        // profile_ObjectType, sampling_frequency_index, private_bits,
+        // channel_configuration, original_copy, home
+        bits.skipBits(12);
+
+        // adts_variable_header
+
+        // copyright_identification_bit, copyright_identification_start
+        bits.skipBits(2);
+
+        unsigned aac_frame_length = bits.getBits(13);
+
+        bits.skipBits(11);  // adts_buffer_fullness
+
+        unsigned number_of_raw_data_blocks_in_frame = bits.getBits(2);
+
+        if (number_of_raw_data_blocks_in_frame == 0) {
+            size_t scan = offset + aac_frame_length;
+
+            offset += 7;
+            if (!protection_absent) {
+                offset += 2;
+            }
+
+            CHECK_LE(scan, buffer->size());
+
+            LOG(VERBOSE)
+                << "found aac raw data block at ["
+                << StringPrintf("0x%08x", offset)
+                << " ; "
+                << StringPrintf("0x%08x", scan)
+                << ")";
+
+            memmove(&buffer->data()[dstOffset], &buffer->data()[offset],
+                    scan - offset);
+
+            dstOffset += scan - offset;
+            offset = scan;
+        } else {
+            // To be implemented.
+            TRESPASS();
+        }
+    }
+    CHECK_EQ(offset, buffer->size());
+
+    buffer->setRange(buffer->offset(), dstOffset);
+}
+
 sp<MediaSource> ATSParser::Stream::getSource(SourceType type) {
     if ((type == AVC_VIDEO && mStreamType == 0x1b)
         || (type == MPEG2ADTS_AUDIO && mStreamType == 0x0f)) {
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
index 7dd3e3f..f68a35b 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
@@ -18,29 +18,160 @@
 
 #include "ARTPSource.h"
 
+#include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/Utils.h>
 
+#include <ctype.h>
 #include <stdint.h>
 
 #define BE_VERBOSE      0
 
 namespace android {
 
+static bool GetAttribute(const char *s, const char *key, AString *value) {
+    value->clear();
+
+    size_t keyLen = strlen(key);
+
+    for (;;) {
+        while (isspace(*s)) {
+            ++s;
+        }
+
+        const char *colonPos = strchr(s, ';');
+
+        size_t len =
+            (colonPos == NULL) ? strlen(s) : colonPos - s;
+
+        if (len >= keyLen + 1 && s[keyLen] == '='
+                && !strncasecmp(s, key, keyLen)) {
+            value->setTo(&s[keyLen + 1], len - keyLen - 1);
+            return true;
+        }
+
+        if (colonPos == NULL) {
+            return false;
+        }
+
+        s = colonPos + 1;
+    }
+}
+
+static bool GetIntegerAttribute(
+        const char *s, const char *key, unsigned *x) {
+    *x = 0;
+
+    AString val;
+    if (!GetAttribute(s, key, &val)) {
+        return false;
+    }
+
+    s = val.c_str();
+    char *end;
+    unsigned y = strtoul(s, &end, 10);
+
+    if (end == s || *end != '\0') {
+        return false;
+    }
+
+    *x = y;
+
+    return true;
+}
+
 // static
-AMPEG4ElementaryAssembler::AMPEG4ElementaryAssembler(const sp<AMessage> &notify)
+AMPEG4ElementaryAssembler::AMPEG4ElementaryAssembler(
+        const sp<AMessage> &notify, const AString &desc, const AString &params)
     : mNotifyMsg(notify),
+      mIsGeneric(false),
+      mParams(params),
+      mSizeLength(0),
+      mIndexLength(0),
+      mIndexDeltaLength(0),
+      mCTSDeltaLength(0),
+      mDTSDeltaLength(0),
+      mRandomAccessIndication(false),
+      mStreamStateIndication(0),
+      mAuxiliaryDataSizeLength(0),
+      mHasAUHeader(false),
       mAccessUnitRTPTime(0),
       mNextExpectedSeqNoValid(false),
       mNextExpectedSeqNo(0),
       mAccessUnitDamaged(false) {
+    mIsGeneric = desc.startsWith("mpeg4-generic/");
+
+    if (mIsGeneric) {
+        AString value;
+        CHECK(GetAttribute(params.c_str(), "mode", &value));
+
+        if (!GetIntegerAttribute(params.c_str(), "sizeLength", &mSizeLength)) {
+            mSizeLength = 0;
+        }
+
+        if (!GetIntegerAttribute(
+                    params.c_str(), "indexLength", &mIndexLength)) {
+            mIndexLength = 0;
+        }
+
+        if (!GetIntegerAttribute(
+                    params.c_str(), "indexDeltaLength", &mIndexDeltaLength)) {
+            mIndexDeltaLength = 0;
+        }
+
+        if (!GetIntegerAttribute(
+                    params.c_str(), "CTSDeltaLength", &mCTSDeltaLength)) {
+            mCTSDeltaLength = 0;
+        }
+
+        if (!GetIntegerAttribute(
+                    params.c_str(), "DTSDeltaLength", &mDTSDeltaLength)) {
+            mDTSDeltaLength = 0;
+        }
+
+        unsigned x;
+        if (!GetIntegerAttribute(
+                    params.c_str(), "randomAccessIndication", &x)) {
+            mRandomAccessIndication = false;
+        } else {
+            CHECK(x == 0 || x == 1);
+            mRandomAccessIndication = (x != 0);
+        }
+
+        if (!GetIntegerAttribute(
+                    params.c_str(), "streamStateIndication",
+                    &mStreamStateIndication)) {
+            mStreamStateIndication = 0;
+        }
+
+        if (!GetIntegerAttribute(
+                    params.c_str(), "auxiliaryDataSizeLength",
+                    &mAuxiliaryDataSizeLength)) {
+            mAuxiliaryDataSizeLength = 0;
+        }
+
+        mHasAUHeader =
+            mSizeLength > 0
+            || mIndexLength > 0
+            || mIndexDeltaLength > 0
+            || mCTSDeltaLength > 0
+            || mDTSDeltaLength > 0
+            || mRandomAccessIndication
+            || mStreamStateIndication > 0;
+    }
 }
 
 AMPEG4ElementaryAssembler::~AMPEG4ElementaryAssembler() {
 }
 
+struct AUHeader {
+    unsigned mSize;
+    unsigned mSerial;
+};
+
 ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket(
         const sp<ARTPSource> &source) {
     List<sp<ABuffer> > *queue = source->queue();
@@ -85,8 +216,116 @@
     }
     mAccessUnitRTPTime = rtpTime;
 
-    mPackets.push_back(buffer);
-    // hexdump(buffer->data(), buffer->size());
+    if (!mIsGeneric) {
+        mPackets.push_back(buffer);
+    } else {
+        // hexdump(buffer->data(), buffer->size());
+
+        CHECK_GE(buffer->size(), 2u);
+        unsigned AU_headers_length = U16_AT(buffer->data());  // in bits
+
+        CHECK_GE(buffer->size(), 2 + (AU_headers_length + 7) / 8);
+
+        List<AUHeader> headers;
+
+        ABitReader bits(buffer->data() + 2, buffer->size() - 2);
+        unsigned numBitsLeft = AU_headers_length;
+
+        unsigned AU_serial = 0;
+        for (;;) {
+            if (numBitsLeft < mSizeLength) { break; }
+
+            unsigned AU_size = bits.getBits(mSizeLength);
+            numBitsLeft -= mSizeLength;
+
+            size_t n = headers.empty() ? mIndexLength : mIndexDeltaLength;
+            if (numBitsLeft < n) { break; }
+
+            unsigned AU_index = bits.getBits(n);
+            numBitsLeft -= n;
+
+            if (headers.empty()) {
+                AU_serial = AU_index;
+            } else {
+                AU_serial += 1 + AU_index;
+            }
+
+            if (mCTSDeltaLength > 0) {
+                if (numBitsLeft < 1) {
+                    break;
+                }
+                --numBitsLeft;
+                if (bits.getBits(1)) {
+                    if (numBitsLeft < mCTSDeltaLength) {
+                        break;
+                    }
+                    bits.skipBits(mCTSDeltaLength);
+                    numBitsLeft -= mCTSDeltaLength;
+                }
+            }
+
+            if (mDTSDeltaLength > 0) {
+                if (numBitsLeft < 1) {
+                    break;
+                }
+                --numBitsLeft;
+                if (bits.getBits(1)) {
+                    if (numBitsLeft < mDTSDeltaLength) {
+                        break;
+                    }
+                    bits.skipBits(mDTSDeltaLength);
+                    numBitsLeft -= mDTSDeltaLength;
+                }
+            }
+
+            if (mRandomAccessIndication) {
+                if (numBitsLeft < 1) {
+                    break;
+                }
+                bits.skipBits(1);
+                --numBitsLeft;
+            }
+
+            if (mStreamStateIndication > 0) {
+                if (numBitsLeft < mStreamStateIndication) {
+                    break;
+                }
+                bits.skipBits(mStreamStateIndication);
+            }
+
+            AUHeader header;
+            header.mSize = AU_size;
+            header.mSerial = AU_serial;
+            headers.push_back(header);
+        }
+
+        size_t offset = 2 + (AU_headers_length + 7) / 8;
+
+        if (mAuxiliaryDataSizeLength > 0) {
+            ABitReader bits(buffer->data() + offset, buffer->size() - offset);
+
+            unsigned auxSize = bits.getBits(mAuxiliaryDataSizeLength);
+
+            offset += (mAuxiliaryDataSizeLength + auxSize + 7) / 8;
+        }
+
+        for (List<AUHeader>::iterator it = headers.begin();
+             it != headers.end(); ++it) {
+            const AUHeader &header = *it;
+
+            CHECK_LE(offset + header.mSize, buffer->size());
+
+            sp<ABuffer> accessUnit = new ABuffer(header.mSize);
+            memcpy(accessUnit->data(), buffer->data() + offset, header.mSize);
+
+            offset += header.mSize;
+
+            CopyTimes(accessUnit, buffer);
+            mPackets.push_back(accessUnit);
+        }
+
+        CHECK_EQ(offset, buffer->size());
+    }
 
     queue->erase(queue->begin());
     ++mNextExpectedSeqNo;
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
index 1566d00..794bbcc 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
@@ -20,6 +20,8 @@
 
 #include "ARTPAssembler.h"
 
+#include <media/stagefright/foundation/AString.h>
+
 #include <utils/List.h>
 #include <utils/RefBase.h>
 
@@ -29,7 +31,9 @@
 struct AMessage;
 
 struct AMPEG4ElementaryAssembler : public ARTPAssembler {
-    AMPEG4ElementaryAssembler(const sp<AMessage> &notify);
+    AMPEG4ElementaryAssembler(
+            const sp<AMessage> &notify, const AString &desc,
+            const AString &params);
 
 protected:
     virtual ~AMPEG4ElementaryAssembler();
@@ -40,6 +44,18 @@
 
 private:
     sp<AMessage> mNotifyMsg;
+    bool mIsGeneric;
+    AString mParams;
+
+    unsigned mSizeLength;
+    unsigned mIndexLength;
+    unsigned mIndexDeltaLength;
+    unsigned mCTSDeltaLength;
+    unsigned mDTSDeltaLength;
+    bool mRandomAccessIndication;
+    unsigned mStreamStateIndication;
+    unsigned mAuxiliaryDataSizeLength;
+    bool mHasAUHeader;
 
     uint32_t mAccessUnitRTPTime;
     bool mNextExpectedSeqNoValid;
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 2d7738b..75b4571 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -247,6 +247,65 @@
     return csd;
 }
 
+// From mpeg4-generic configuration data.
+sp<ABuffer> MakeAACCodecSpecificData2(const char *params) {
+    AString val;
+    unsigned long objectType;
+    if (GetAttribute(params, "objectType", &val)) {
+        const char *s = val.c_str();
+        char *end;
+        objectType = strtoul(s, &end, 10);
+        CHECK(end > s && *end == '\0');
+    } else {
+        objectType = 0x40;  // Audio ISO/IEC 14496-3
+    }
+
+    CHECK(GetAttribute(params, "config", &val));
+
+    sp<ABuffer> config = decodeHex(val);
+    CHECK(config != NULL);
+
+    // Make sure size fits into a single byte and doesn't have to
+    // be encoded.
+    CHECK_LT(20 + config->size(), 128u);
+
+    const uint8_t *data = config->data();
+
+    static const uint8_t kStaticESDS[] = {
+        0x03, 22,
+        0x00, 0x00,     // ES_ID
+        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
+
+        0x04, 17,
+        0x40,                       // Audio ISO/IEC 14496-3
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+
+        0x05, 2,
+        // AudioSpecificInfo follows
+    };
+
+    sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + config->size());
+    uint8_t *dst = csd->data();
+    *dst++ = 0x03;
+    *dst++ = 20 + config->size();
+    *dst++ = 0x00;  // ES_ID
+    *dst++ = 0x00;
+    *dst++ = 0x00;  // streamDependenceFlag, URL_Flag, OCRstreamFlag
+    *dst++ = 0x04;
+    *dst++ = 15 + config->size();
+    *dst++ = objectType;
+    for (int i = 0; i < 12; ++i) { *dst++ = 0x00; }
+    *dst++ = 0x05;
+    *dst++ = config->size();
+    memcpy(dst, config->data(), config->size());
+
+    // hexdump(csd->data(), csd->size());
+
+    return csd;
+}
+
 static size_t GetSizeWidth(size_t x) {
     size_t n = 1;
     while (x > 127) {
@@ -560,6 +619,30 @@
 
         mFormat->setInt32(kKeyWidth, width);
         mFormat->setInt32(kKeyHeight, height);
+    } else if (!strncmp(desc.c_str(), "mpeg4-generic/", 14)) {
+        AString val;
+        if (!GetAttribute(params.c_str(), "mode", &val)
+                || (strcasecmp(val.c_str(), "AAC-lbr")
+                    && strcasecmp(val.c_str(), "AAC-hbr"))) {
+            mInitCheck = ERROR_UNSUPPORTED;
+            return;
+        }
+
+        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+
+        int32_t sampleRate, numChannels;
+        ASessionDescription::ParseFormatDesc(
+                desc.c_str(), &sampleRate, &numChannels);
+
+        mFormat->setInt32(kKeySampleRate, sampleRate);
+        mFormat->setInt32(kKeyChannelCount, numChannels);
+
+        sp<ABuffer> codecSpecificData =
+            MakeAACCodecSpecificData2(params.c_str());
+
+        mFormat->setData(
+                kKeyESDS, 0,
+                codecSpecificData->data(), codecSpecificData->size());
     } else {
         mInitCheck = ERROR_UNSUPPORTED;
     }
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 12f8f32..10c9e02 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -362,7 +362,6 @@
     if (receiveRTP) {
         err = parseRTP(s, buffer);
     } else {
-        ++s->mNumRTCPPacketsReceived;
         err = parseRTCP(s, buffer);
     }
 
@@ -456,6 +455,12 @@
 }
 
 status_t ARTPConnection::parseRTCP(StreamInfo *s, const sp<ABuffer> &buffer) {
+    if (s->mNumRTCPPacketsReceived++ == 0) {
+        sp<AMessage> notify = s->mNotifyMsg->dup();
+        notify->setInt32("first-rtcp", true);
+        notify->post();
+    }
+
     const uint8_t *data = buffer->data();
     size_t size = buffer->size();
 
@@ -626,7 +631,6 @@
     if (it->mRTPSocket == index) {
         err = parseRTP(s, buffer);
     } else {
-        ++s->mNumRTCPPacketsReceived;
         err = parseRTCP(s, buffer);
     }
 }
diff --git a/media/libstagefright/rtsp/ARTPSession.cpp b/media/libstagefright/rtsp/ARTPSession.cpp
index f60c1a9..8ce93b7 100644
--- a/media/libstagefright/rtsp/ARTPSession.cpp
+++ b/media/libstagefright/rtsp/ARTPSession.cpp
@@ -125,6 +125,14 @@
     switch (msg->what()) {
         case kWhatAccessUnitComplete:
         {
+            int32_t firstRTCP;
+            if (msg->findInt32("first-rtcp", &firstRTCP)) {
+                // There won't be an access unit here, it's just a notification
+                // that the data communication worked since we got the first
+                // rtcp packet.
+                break;
+            }
+
             size_t trackIndex;
             CHECK(msg->findSize("track-index", &trackIndex));
 
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index 775c4ee..9656ba2 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -64,8 +64,9 @@
         mAssembler = new AAMRAssembler(notify, false /* isWide */, params);
     } else  if (!strncmp(desc.c_str(), "AMR-WB/", 7)) {
         mAssembler = new AAMRAssembler(notify, true /* isWide */, params);
-    } else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)) {
-        mAssembler = new AMPEG4ElementaryAssembler(notify);
+    } else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)
+            || !strncmp(desc.c_str(), "mpeg4-generic/", 14)) {
+        mAssembler = new AMPEG4ElementaryAssembler(notify, desc, params);
         mIssueFIRRequests = true;
     } else {
         TRESPASS();
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 3d8d86b..0aefd58 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -82,7 +82,8 @@
           mFirstAccessUnitNTP(0),
           mNumAccessUnitsReceived(0),
           mCheckPending(false),
-          mTryTCPInterleaving(false) {
+          mTryTCPInterleaving(false),
+          mReceivedFirstRTCPPacket(false) {
         mNetLooper->setName("rtsp net");
         mNetLooper->start(false /* runOnCallingThread */,
                           false /* canCallJava */,
@@ -199,31 +200,35 @@
                         break;
                     }
 
-                    CHECK_EQ(response->mStatusCode, 200u);
-
-                    mSessionDesc = new ASessionDescription;
-
-                    mSessionDesc->setTo(
-                            response->mContent->data(),
-                            response->mContent->size());
-
-                    CHECK(mSessionDesc->isValid());
-
-                    ssize_t i = response->mHeaders.indexOfKey("content-base");
-                    if (i >= 0) {
-                        mBaseURL = response->mHeaders.valueAt(i);
+                    if (response->mStatusCode != 200) {
+                        result = UNKNOWN_ERROR;
                     } else {
-                        i = response->mHeaders.indexOfKey("content-location");
+                        mSessionDesc = new ASessionDescription;
+
+                        mSessionDesc->setTo(
+                                response->mContent->data(),
+                                response->mContent->size());
+
+                        CHECK(mSessionDesc->isValid());
+
+                        ssize_t i = response->mHeaders.indexOfKey("content-base");
                         if (i >= 0) {
                             mBaseURL = response->mHeaders.valueAt(i);
                         } else {
-                            mBaseURL = mSessionURL;
+                            i = response->mHeaders.indexOfKey("content-location");
+                            if (i >= 0) {
+                                mBaseURL = response->mHeaders.valueAt(i);
+                            } else {
+                                mBaseURL = mSessionURL;
+                            }
                         }
-                    }
 
-                    CHECK_GT(mSessionDesc->countTracks(), 1u);
-                    setupTrack(1);
-                } else {
+                        CHECK_GT(mSessionDesc->countTracks(), 1u);
+                        setupTrack(1);
+                    }
+                }
+
+                if (result != OK) {
                     sp<AMessage> reply = new AMessage('disc', id());
                     mConn->disconnect(reply);
                 }
@@ -247,6 +252,39 @@
                 LOG(INFO) << "SETUP(" << index << ") completed with result "
                      << result << " (" << strerror(-result) << ")";
 
+                if (result == OK) {
+                    CHECK(track != NULL);
+
+                    sp<RefBase> obj;
+                    CHECK(msg->findObject("response", &obj));
+                    sp<ARTSPResponse> response =
+                        static_cast<ARTSPResponse *>(obj.get());
+
+                    if (response->mStatusCode != 200) {
+                        result = UNKNOWN_ERROR;
+                    } else {
+                        ssize_t i = response->mHeaders.indexOfKey("session");
+                        CHECK_GE(i, 0);
+
+                        mSessionID = response->mHeaders.valueAt(i);
+                        i = mSessionID.find(";");
+                        if (i >= 0) {
+                            // Remove options, i.e. ";timeout=90"
+                            mSessionID.erase(i, mSessionID.size() - i);
+                        }
+
+                        sp<AMessage> notify = new AMessage('accu', id());
+                        notify->setSize("track-index", trackIndex);
+
+                        mRTPConn->addStream(
+                                track->mRTPSocket, track->mRTCPSocket,
+                                mSessionDesc, index,
+                                notify, track->mUsingInterleavedTCP);
+
+                        mSetupTracksSuccessful = true;
+                    }
+                }
+
                 if (result != OK) {
                     if (track) {
                         if (!track->mUsingInterleavedTCP) {
@@ -256,37 +294,6 @@
 
                         mTracks.removeItemsAt(trackIndex);
                     }
-                } else {
-                    CHECK(track != NULL);
-
-                    sp<RefBase> obj;
-                    CHECK(msg->findObject("response", &obj));
-                    sp<ARTSPResponse> response =
-                        static_cast<ARTSPResponse *>(obj.get());
-
-                    CHECK_EQ(response->mStatusCode, 200u);
-
-                    ssize_t i = response->mHeaders.indexOfKey("session");
-                    CHECK_GE(i, 0);
-
-                    if (index == 1) {
-                        mSessionID = response->mHeaders.valueAt(i);
-                        i = mSessionID.find(";");
-                        if (i >= 0) {
-                            // Remove options, i.e. ";timeout=90"
-                            mSessionID.erase(i, mSessionID.size() - i);
-                        }
-                    }
-
-                    sp<AMessage> notify = new AMessage('accu', id());
-                    notify->setSize("track-index", trackIndex);
-
-                    mRTPConn->addStream(
-                            track->mRTPSocket, track->mRTCPSocket,
-                            mSessionDesc, index,
-                            notify, track->mUsingInterleavedTCP);
-
-                    mSetupTracksSuccessful = true;
                 }
 
                 ++index;
@@ -355,6 +362,12 @@
                     }
                 }
                 mTracks.clear();
+                mSetupTracksSuccessful = false;
+                mSeekPending = false;
+                mFirstAccessUnit = true;
+                mFirstAccessUnitNTP = 0;
+                mNumAccessUnitsReceived = 0;
+                mReceivedFirstRTCPPacket = false;
 
                 sp<AMessage> reply = new AMessage('tear', id());
 
@@ -424,6 +437,12 @@
 
             case 'accu':
             {
+                int32_t firstRTCP;
+                if (msg->findInt32("first-rtcp", &firstRTCP)) {
+                    mReceivedFirstRTCPPacket = true;
+                    break;
+                }
+
                 ++mNumAccessUnitsReceived;
 
                 if (!mCheckPending) {
@@ -612,7 +631,7 @@
 
             case 'tiou':
             {
-                if (mFirstAccessUnit) {
+                if (!mReceivedFirstRTCPPacket) {
                     if (mTryTCPInterleaving) {
                         LOG(WARNING) << "Never received any data, disconnecting.";
                         (new AMessage('abor', id()))->post();
@@ -747,6 +766,7 @@
     int64_t mNumAccessUnitsReceived;
     bool mCheckPending;
     bool mTryTCPInterleaving;
+    bool mReceivedFirstRTCPPacket;
 
     struct TrackInfo {
         AString mURL;
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
index 899b34a..c8cb016 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -93,6 +93,10 @@
                                             MtpObjectFormat format) = 0;
 
     virtual MtpProperty*            getDevicePropertyDesc(MtpDeviceProperty property) = 0;
+
+    virtual void                    sessionStarted() = 0;
+
+    virtual void                    sessionEnded() = 0;
 };
 
 }; // namespace android
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 1e64e4f..c982114 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -185,6 +185,9 @@
             LOGV("skipping response\n");
         }
     }
+
+    if (mSessionOpen)
+        mDatabase->sessionEnded();
 }
 
 void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
@@ -346,6 +349,9 @@
     }
     mSessionID = mRequest.getParameter(1);
     mSessionOpen = true;
+
+    mDatabase->sessionStarted();
+
     return MTP_RESPONSE_OK;
 }
 
@@ -354,6 +360,7 @@
         return MTP_RESPONSE_SESSION_NOT_OPEN;
     mSessionID = 0;
     mSessionOpen = false;
+    mDatabase->sessionEnded();
     return MTP_RESPONSE_OK;
 }
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index ff31470..1acdaaf 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1781,6 +1781,14 @@
                 if (chain != 0 && chain->setVolume_l(&vl, &vr)) {
                     // Do not ramp volume is volume is controlled by effect
                     param = AudioMixer::VOLUME;
+                    track->mHasVolumeController = true;
+                } else {
+                    // force no volume ramp when volume controller was just disabled or removed
+                    // from effect chain to avoid volume spike
+                    if (track->mHasVolumeController) {
+                        param = AudioMixer::VOLUME;
+                    }
+                    track->mHasVolumeController = false;
                 }
 
                 // Convert volumes from 8.24 to 4.12 format
@@ -2901,7 +2909,8 @@
             const sp<IMemory>& sharedBuffer,
             int sessionId)
     :   TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer, sessionId),
-    mMute(false), mSharedBuffer(sharedBuffer), mName(-1), mMainBuffer(NULL), mAuxBuffer(NULL), mAuxEffectId(0)
+    mMute(false), mSharedBuffer(sharedBuffer), mName(-1), mMainBuffer(NULL), mAuxBuffer(NULL),
+    mAuxEffectId(0), mHasVolumeController(false)
 {
     if (mCblk != NULL) {
         sp<ThreadBase> baseThread = thread.promote();
@@ -5371,7 +5380,7 @@
         return;
     }
 
-    if (mState == ACTIVE || mState == STOPPING || mState == STOPPED || mState == RESTART) {
+    if (isProcessEnabled()) {
         // do 32 bit to 16 bit conversion for auxiliary effect input buffer
         if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
             AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32,
@@ -5600,6 +5609,8 @@
 
         // going from enabled to disabled
         case RESTART:
+            mState = STOPPED;
+            break;
         case STARTING:
             mState = IDLE;
             break;
@@ -5632,6 +5643,21 @@
     }
 }
 
+bool AudioFlinger::EffectModule::isProcessEnabled()
+{
+    switch (mState) {
+    case RESTART:
+    case ACTIVE:
+    case STOPPING:
+    case STOPPED:
+        return true;
+    case IDLE:
+    case STARTING:
+    default:
+        return false;
+    }
+}
+
 status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
 {
     Mutex::Autolock _l(mLock);
@@ -5639,7 +5665,7 @@
 
     // Send volume indication if EFFECT_FLAG_VOLUME_IND is set and read back altered volume
     // if controller flag is set (Note that controller == TRUE => EFFECT_FLAG_VOLUME_CTRL set)
-    if ((mState >= ACTIVE) &&
+    if (isProcessEnabled() &&
             ((mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL ||
             (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_IND)) {
         status_t cmdStatus;
@@ -6288,7 +6314,7 @@
 
     // first update volume controller
     for (size_t i = size; i > 0; i--) {
-        if ((mEffects[i - 1]->state() >= EffectModule::ACTIVE) &&
+        if (mEffects[i - 1]->isProcessEnabled() &&
             (mEffects[i - 1]->desc().flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL) {
             ctrlIdx = i - 1;
             hasControl = true;
@@ -6304,9 +6330,6 @@
         return hasControl;
     }
 
-    if (mVolumeCtrlIdx != -1) {
-        hasControl = true;
-    }
     mVolumeCtrlIdx = ctrlIdx;
     mLeftVolume = newLeft;
     mRightVolume = newRight;
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 51881f0..5917632 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -514,6 +514,7 @@
             int16_t             *mMainBuffer;
             int32_t             *mAuxBuffer;
             int                 mAuxEffectId;
+            bool                mHasVolumeController;
         };  // end of Track
 
 
@@ -965,6 +966,7 @@
         }
         status_t    setEnabled(bool enabled);
         bool isEnabled();
+        bool isProcessEnabled();
 
         void        setInBuffer(int16_t *buffer) { mConfig.inputCfg.buffer.s16 = buffer; }
         int16_t     *inBuffer() { return mConfig.inputCfg.buffer.s16; }
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c6a9909..d1fbf17 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -336,11 +336,6 @@
     int callingPid = getCallingPid();
     LOG1("Client::~Client E (pid %d, this %p)", callingPid, this);
 
-    // Clean up the ANativeWindow
-    if (mSurface != 0) {
-        setPreviewDisplay(0);
-    }
-
     // set mClientPid to let disconnet() tear down the hardware
     mClientPid = callingPid;
     disconnect();