Merge "Use a status_t return type for GL functors"
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 30be7fa..52a9293 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -4,19 +4,18 @@
 
 LOCAL_SRC_FILES:=       \
 	stagefright.cpp \
+	jpeg.cpp	\
 	SineSource.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright libmedia libmedia_native libutils libbinder libstagefright_foundation \
-        libskia libgui
+        libjpeg libgui
 
 LOCAL_C_INCLUDES:= \
-	$(JNI_H_INCLUDE) \
 	frameworks/base/media/libstagefright \
 	frameworks/base/media/libstagefright/include \
 	$(TOP)/frameworks/native/include/media/openmax \
-	external/skia/include/core \
-	external/skia/include/images \
+	external/jpeg \
 
 LOCAL_CFLAGS += -Wno-multichar
 
@@ -38,7 +37,6 @@
 	libstagefright liblog libutils libbinder libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
-	$(JNI_H_INCLUDE) \
 	frameworks/base/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax
 
@@ -62,7 +60,6 @@
 	libstagefright liblog libutils libbinder libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
-	$(JNI_H_INCLUDE) \
 	frameworks/base/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax
 
@@ -87,7 +84,6 @@
 	libstagefright liblog libutils libbinder libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
-	$(JNI_H_INCLUDE) \
 	frameworks/base/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax
 
@@ -111,7 +107,6 @@
         libstagefright_foundation libmedia libmedia_native
 
 LOCAL_C_INCLUDES:= \
-	$(JNI_H_INCLUDE) \
 	frameworks/base/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax
 
@@ -135,7 +130,6 @@
         libmedia libmedia_native libgui libcutils libui
 
 LOCAL_C_INCLUDES:= \
-	$(JNI_H_INCLUDE) \
 	frameworks/base/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax
 
@@ -160,7 +154,6 @@
         libmedia libmedia_native libgui libcutils libui
 
 LOCAL_C_INCLUDES:= \
-	$(JNI_H_INCLUDE) \
 	frameworks/base/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax
 
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index fea62cc..cf2909e 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -28,6 +28,7 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/NuMediaExtractor.h>
 #include <gui/SurfaceComposerClient.h>
@@ -36,7 +37,9 @@
     fprintf(stderr, "usage: %s [-a] use audio\n"
                     "\t\t[-v] use video\n"
                     "\t\t[-p] playback\n"
-                    "\t\t[-S] allocate buffers from a surface\n", me);
+                    "\t\t[-S] allocate buffers from a surface\n"
+                    "\t\t[-D] decrypt input buffers\n",
+                    me);
 
     exit(1);
 }
@@ -63,7 +66,8 @@
         const char *path,
         bool useAudio,
         bool useVideo,
-        const android::sp<android::Surface> &surface) {
+        const android::sp<android::Surface> &surface,
+        bool decryptInputBuffers) {
     using namespace android;
 
     static int64_t kTimeout = 500ll;
@@ -109,13 +113,31 @@
         state->mNumBuffersDecoded = 0;
         state->mIsAudio = isAudio;
 
-        state->mCodec = MediaCodec::CreateByType(
-                looper, mime.c_str(), false /* encoder */);
+        if (decryptInputBuffers && !isAudio) {
+            static const MediaCodecList *list = MediaCodecList::getInstance();
+
+            ssize_t index =
+                list->findCodecByType(mime.c_str(), false /* encoder */);
+
+            CHECK_GE(index, 0);
+
+            const char *componentName = list->getCodecName(index);
+
+            AString fullName = componentName;
+            fullName.append(".secure");
+
+            state->mCodec = MediaCodec::CreateByComponentName(
+                    looper, fullName.c_str());
+        } else {
+            state->mCodec = MediaCodec::CreateByType(
+                    looper, mime.c_str(), false /* encoder */);
+        }
 
         CHECK(state->mCodec != NULL);
 
         err = state->mCodec->configure(
-                format, isVideo ? surface : NULL, 0 /* flags */);
+                format, isVideo ? surface : NULL,
+                decryptInputBuffers ? MediaCodec::CONFIGURE_FLAG_SECURE : 0);
 
         CHECK_EQ(err, (status_t)OK);
 
@@ -202,12 +224,24 @@
                     err = extractor->getSampleTime(&timeUs);
                     CHECK_EQ(err, (status_t)OK);
 
+                    uint32_t bufferFlags = 0;
+
+                    uint32_t sampleFlags;
+                    err = extractor->getSampleFlags(&sampleFlags);
+                    CHECK_EQ(err, (status_t)OK);
+
+                    if (sampleFlags & NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED) {
+                        CHECK(decryptInputBuffers);
+
+                        bufferFlags |= MediaCodec::BUFFER_FLAG_ENCRYPTED;
+                    }
+
                     err = state->mCodec->queueInputBuffer(
                             index,
                             0 /* offset */,
                             buffer->size(),
                             timeUs,
-                            0 /* flags */);
+                            bufferFlags);
 
                     CHECK_EQ(err, (status_t)OK);
 
@@ -341,9 +375,10 @@
     bool useVideo = false;
     bool playback = false;
     bool useSurface = false;
+    bool decryptInputBuffers = false;
 
     int res;
-    while ((res = getopt(argc, argv, "havpS")) >= 0) {
+    while ((res = getopt(argc, argv, "havpSD")) >= 0) {
         switch (res) {
             case 'a':
             {
@@ -369,6 +404,12 @@
                 break;
             }
 
+            case 'D':
+            {
+                decryptInputBuffers = true;
+                break;
+            }
+
             case '?':
             case 'h':
             default:
@@ -440,7 +481,8 @@
         player->stop();
         player->reset();
     } else {
-        decode(looper, argv[0], useAudio, useVideo, surface);
+        decode(looper, argv[0],
+               useAudio, useVideo, surface, decryptInputBuffers);
     }
 
     if (playback || (useSurface && useVideo)) {
diff --git a/cmds/stagefright/jpeg.cpp b/cmds/stagefright/jpeg.cpp
new file mode 100644
index 0000000..7e859c3
--- /dev/null
+++ b/cmds/stagefright/jpeg.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <setjmp.h>
+#include <stdio.h>
+
+extern "C" {
+#include "jpeglib.h"
+}
+
+static inline uint8_t from565to8(uint16_t p, int start, int bits) {
+    uint8_t c = (p >> start) & ((1 << bits) - 1);
+    return (c << (8 - bits)) | (c >> (bits - (8 - bits)));
+}
+
+struct sf_jpeg_error_mgr {
+    struct jpeg_error_mgr jerr;
+    jmp_buf longjmp_buffer;
+};
+
+void sf_jpeg_error_exit(j_common_ptr cinfo) {
+    struct sf_jpeg_error_mgr *sf_err = (struct sf_jpeg_error_mgr *)cinfo->err;
+    longjmp(sf_err->longjmp_buffer, 0);
+}
+
+int writeJpegFile(const char *filename, uint8_t *frame, int width, int height) {
+    struct sf_jpeg_error_mgr sf_err;
+    struct jpeg_compress_struct cinfo;
+    uint8_t row_data[width * 3];
+    JSAMPROW row_pointer = row_data;
+    FILE *f;
+
+    f = fopen(filename, "w");
+    if (!f) {
+        return -errno;
+    }
+
+    cinfo.err = jpeg_std_error(&sf_err.jerr);
+    sf_err.jerr.error_exit = sf_jpeg_error_exit;
+    if (setjmp(sf_err.longjmp_buffer)) {
+        jpeg_destroy_compress(&cinfo);
+        fclose(f);
+        return -1;
+    }
+
+    jpeg_create_compress(&cinfo);
+    jpeg_stdio_dest(&cinfo, f);
+
+    cinfo.image_width = width;
+    cinfo.image_height = height;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_RGB;
+
+    jpeg_set_defaults(&cinfo);
+    jpeg_set_quality(&cinfo, 80, TRUE);
+
+    jpeg_start_compress(&cinfo, TRUE);
+
+    for (int row = 0; row < height; row++) {
+        uint16_t *src = (uint16_t *)(frame + row * width * 2);
+        uint8_t *dst = row_data;
+        for (int col = 0; col < width; col++) {
+            dst[0] = from565to8(*src, 11, 5);
+            dst[1] = from565to8(*src, 5, 6);
+            dst[2] = from565to8(*src, 0, 5);
+            dst += 3;
+            src++;
+        }
+        jpeg_write_scanlines(&cinfo, &row_pointer, 1);
+    }
+
+    jpeg_finish_compress(&cinfo);
+    jpeg_destroy_compress(&cinfo);
+
+    fclose(f);
+    return 0;
+}
diff --git a/cmds/stagefright/jpeg.h b/cmds/stagefright/jpeg.h
new file mode 100644
index 0000000..ce86cf2
--- /dev/null
+++ b/cmds/stagefright/jpeg.h
@@ -0,0 +1,6 @@
+#ifndef _STAGEFRIGHT_JPEG_H_
+#define _STAGEFRIGHT_JPEG_H_
+
+int writeJpegFile(const char *filename, uint8_t *frame, int width, int height);
+
+#endif
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index 64df5d1..3bbfbdc 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -287,6 +287,11 @@
 
             msg->setInt32("channel-count", numChannels);
             msg->setInt32("sample-rate", sampleRate);
+
+            int32_t isADTS;
+            if (meta->findInt32(kKeyIsADTS, &isADTS) && isADTS != 0) {
+                msg->setInt32("is-adts", true);
+            }
         }
 
         uint32_t type;
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index dab2e0f..d70c862 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "jpeg.h"
 #include "SineSource.h"
 
 #include <binder/IServiceManager.h>
@@ -49,8 +50,6 @@
 #include <media/stagefright/MPEG4Writer.h>
 
 #include <private/media/VideoFrame.h>
-#include <SkBitmap.h>
-#include <SkImageEncoder.h>
 
 #include <fcntl.h>
 
@@ -787,16 +786,9 @@
 
                 VideoFrame *frame = (VideoFrame *)mem->pointer();
 
-                SkBitmap bitmap;
-                bitmap.setConfig(
-                        SkBitmap::kRGB_565_Config, frame->mWidth, frame->mHeight);
-
-                bitmap.setPixels((uint8_t *)frame + sizeof(VideoFrame));
-
-                CHECK(SkImageEncoder::EncodeFile(
-                            "/sdcard/out.jpg", bitmap,
-                            SkImageEncoder::kJPEG_Type,
-                            SkImageEncoder::kDefaultQuality));
+                CHECK_EQ(writeJpegFile("/sdcard/out.jpg",
+                            (uint8_t *)frame + sizeof(VideoFrame),
+                            frame->mWidth, frame->mHeight), 0);
             }
 
             {
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 7df6668..5bfb65b 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -354,7 +354,6 @@
                                 audio_format_t format,
                                 uint32_t channelMask,
                                 int frameCount,
-                                uint32_t flags,
                                 audio_io_handle_t input);
             audio_io_handle_t getInput_l();
             status_t restoreRecord_l(audio_track_cblk_t*& cblk);
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 0f39cf3..8239b0e 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -43,6 +43,14 @@
 public:
     DECLARE_META_INTERFACE(AudioFlinger);
 
+    // or-able bits shared by createTrack and openRecord, but not all combinations make sense
+    enum {
+        TRACK_DEFAULT = 0,  // client requests a default AudioTrack
+        TRACK_TIMED   = 1,  // client requests a TimedAudioTrack
+        TRACK_FAST    = 2,  // client requests a fast AudioTrack
+    };
+    typedef uint32_t track_flags_t;
+
     /* create an audio track and registers it with AudioFlinger.
      * return null if the track cannot be created.
      */
@@ -53,10 +61,9 @@
                                 audio_format_t format,
                                 uint32_t channelMask,
                                 int frameCount,
-                                uint32_t flags,
+                                track_flags_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 audio_io_handle_t output,
-                                bool isTimed,
                                 int *sessionId,
                                 status_t *status) = 0;
 
@@ -67,7 +74,7 @@
                                 audio_format_t format,
                                 uint32_t channelMask,
                                 int frameCount,
-                                uint32_t flags,
+                                track_flags_t flags,
                                 int *sessionId,
                                 status_t *status) = 0;
 
diff --git a/include/media/ICrypto.h b/include/media/ICrypto.h
new file mode 100644
index 0000000..916abe0
--- /dev/null
+++ b/include/media/ICrypto.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IInterface.h>
+#include <media/stagefright/foundation/ABase.h>
+
+#ifndef ANDROID_ICRYPTO_H_
+
+#define ANDROID_ICRYPTO_H_
+
+namespace android {
+
+struct ICrypto : public IInterface {
+    DECLARE_META_INTERFACE(Crypto);
+
+    virtual status_t initialize() = 0;
+    virtual status_t terminate() = 0;
+
+    virtual status_t setEntitlementKey(
+            const void *key, size_t keyLength) = 0;
+
+    virtual status_t setEntitlementControlMessage(
+            const void *msg, size_t msgLength) = 0;
+
+    // "dstData" is in media_server's address space (but inaccessible).
+    virtual ssize_t decryptVideo(
+            const void *iv, size_t ivLength,
+            const void *srcData, size_t srcDataSize,
+            void *dstData, size_t dstDataOffset) = 0;
+
+    // "dstData" is in the calling process' address space.
+    virtual ssize_t decryptAudio(
+            const void *iv, size_t ivLength,
+            const void *srcData, size_t srcDataSize,
+            void *dstData, size_t dstDataSize) = 0;
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(ICrypto);
+};
+
+struct BnCrypto : public BnInterface<ICrypto> {
+    virtual status_t onTransact(
+            uint32_t code, const Parcel &data, Parcel *reply,
+            uint32_t flags = 0);
+};
+
+}  // namespace android
+
+#endif // ANDROID_ICRYPTO_H_
+
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index 4f46fcd..76c45a0 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -31,6 +31,7 @@
 
 namespace android {
 
+struct ICrypto;
 class IMediaRecorder;
 class IOMX;
 struct IStreamSource;
@@ -47,6 +48,7 @@
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) = 0;
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) = 0;
     virtual sp<IOMX>            getOMX() = 0;
+    virtual sp<ICrypto>         makeCrypto() = 0;
 
     // codecs and audio devices usage tracking for the battery app
     enum BatteryDataBits {
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index a295e9a..be1b2fc 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -26,8 +26,6 @@
 #include <OMX_Core.h>
 #include <OMX_Video.h>
 
-#include "jni.h"
-
 namespace android {
 
 class IMemory;
diff --git a/include/media/JetPlayer.h b/include/media/JetPlayer.h
index 38a3e44..0616bf0 100644
--- a/include/media/JetPlayer.h
+++ b/include/media/JetPlayer.h
@@ -18,7 +18,6 @@
 #define JETPLAYER_H_
 
 #include <utils/threads.h>
-#include <nativehelper/jni.h>
 
 #include <libsonivox/jet.h>
 #include <libsonivox/eas_types.h>
@@ -40,7 +39,7 @@
     static const int JET_NUMQUEUEDSEGMENT_UPDATE = 3;
     static const int JET_PAUSE_UPDATE            = 4;
 
-    JetPlayer(jobject javaJetPlayer,
+    JetPlayer(void *javaJetPlayer,
             int maxTracks = 32,
             int trackBufferSize = 1200);
     ~JetPlayer();
@@ -75,7 +74,7 @@
 
     jetevent_callback   mEventCallback;
 
-    jobject             mJavaJetPlayerRef;
+    void*               mJavaJetPlayerRef;
     Mutex               mMutex; // mutex to sync the render and playback thread with the JET calls
     pid_t               mTid;
     Condition           mCondition;
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index fa1a416..7d7af63 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -89,6 +89,10 @@
         kPortIndexOutput = 1
     };
 
+    enum {
+        kFlagIsSecure   = 1,
+    };
+
     struct BufferInfo {
         enum Status {
             OWNED_BY_US,
@@ -118,6 +122,7 @@
     sp<FlushingState> mFlushingState;
 
     AString mComponentName;
+    uint32_t mFlags;
     uint32_t mQuirks;
     sp<IOMX> mOMX;
     IOMX::node_id mNode;
@@ -176,7 +181,8 @@
 
     status_t setupAACCodec(
             bool encoder,
-            int32_t numChannels, int32_t sampleRate, int32_t bitRate);
+            int32_t numChannels, int32_t sampleRate, int32_t bitRate,
+            bool isADTS);
 
     status_t selectAudioPortFormat(
             OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE desiredFormat);
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 72ac56a..0fc88e1 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -27,18 +27,21 @@
 struct ABuffer;
 struct ACodec;
 struct AMessage;
+struct ICrypto;
 struct SoftwareRenderer;
 struct SurfaceTextureClient;
 
 struct MediaCodec : public AHandler {
     enum ConfigureFlags {
         CONFIGURE_FLAG_ENCODE   = 1,
+        CONFIGURE_FLAG_SECURE   = 2,
     };
 
     enum BufferFlags {
         BUFFER_FLAG_SYNCFRAME   = 1,
         BUFFER_FLAG_CODECCONFIG = 2,
         BUFFER_FLAG_EOS         = 4,
+        BUFFER_FLAG_ENCRYPTED   = 8,
     };
 
     static sp<MediaCodec> CreateByType(
@@ -137,11 +140,13 @@
         kFlagStickyError                = 8,
         kFlagDequeueInputPending        = 16,
         kFlagDequeueOutputPending       = 32,
+        kFlagIsSecure                   = 64,
     };
 
     struct BufferInfo {
         void *mBufferID;
         sp<ABuffer> mData;
+        sp<ABuffer> mEncryptedData;
         sp<AMessage> mNotify;
         bool mOwnedByClient;
     };
@@ -165,6 +170,8 @@
     int32_t mDequeueOutputTimeoutGeneration;
     uint32_t mDequeueOutputReplyID;
 
+    sp<ICrypto> mCrypto;
+
     MediaCodec(const sp<ALooper> &looper);
 
     static status_t PostAndAwaitResponse(
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index c3ccb56..639446e 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -128,6 +128,12 @@
     kKeyTextFormatData    = 'text',  // raw data
 
     kKeyRequiresSecureBuffers = 'secu',  // bool (int32_t)
+
+    kKeyScrambling        = 'scrm',  // int32_t
+    kKeyEMM               = 'emm ',  // raw data
+    kKeyECM               = 'ecm ',  // raw data
+
+    kKeyIsADTS            = 'adts',  // bool (int32_t)
 };
 
 enum {
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index 96efdff..07c7be5 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -31,6 +31,11 @@
 struct MediaSource;
 
 struct NuMediaExtractor : public RefBase {
+    enum SampleFlags {
+        SAMPLE_FLAG_SYNC        = 1,
+        SAMPLE_FLAG_ENCRYPTED   = 2,
+    };
+
     NuMediaExtractor();
 
     status_t setDataSource(const char *path);
@@ -46,6 +51,7 @@
     status_t readSampleData(const sp<ABuffer> &buffer);
     status_t getSampleTrackIndex(size_t *trackIndex);
     status_t getSampleTime(int64_t *sampleTimeUs);
+    status_t getSampleFlags(uint32_t *sampleFlags);
 
 protected:
     virtual ~NuMediaExtractor();
@@ -61,7 +67,9 @@
         status_t mFinalResult;
         MediaBuffer *mSample;
         int64_t mSampleTimeUs;
-        uint32_t mFlags;  // bitmask of "TrackFlags"
+        uint32_t mSampleFlags;
+
+        uint32_t mTrackFlags;  // bitmask of "TrackFlags"
     };
 
     sp<MediaExtractor> mImpl;
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 7c612ba..7d51dee 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -238,7 +238,11 @@
     void setComponentRole();
 
     void setAMRFormat(bool isWAMR, int32_t bitRate);
-    status_t setAACFormat(int32_t numChannels, int32_t sampleRate, int32_t bitRate);
+
+    status_t setAACFormat(
+            int32_t numChannels, int32_t sampleRate, int32_t bitRate,
+            bool isADTS);
+
     void setG711Format(int32_t numChannels);
 
     status_t setVideoPortFormatType(
diff --git a/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h
index 54baab6..936b057 100644
--- a/include/media/stagefright/SurfaceMediaSource.h
+++ b/include/media/stagefright/SurfaceMediaSource.h
@@ -111,7 +111,7 @@
     // Make sure this is called when the mutex is locked
     virtual status_t onFrameReceivedLocked();
 
-    virtual status_t setScalingMode(int mode) { } // no op for encoding
+    virtual status_t setScalingMode(int mode) { return OK; } // no op for encoding
     virtual int query(int what, int* value);
 
     // Just confirming to the ISurfaceTexture interface as of now
diff --git a/include/media/stagefright/foundation/AString.h b/include/media/stagefright/foundation/AString.h
index 55ade64..0f8f1e1 100644
--- a/include/media/stagefright/foundation/AString.h
+++ b/include/media/stagefright/foundation/AString.h
@@ -73,6 +73,7 @@
     int compare(const AString &other) const;
 
     bool startsWith(const char *prefix) const;
+    bool endsWith(const char *suffix) const;
 
     void tolower();
 
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 51c8b68..bdb1a1c 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <new>
+#include <time.h>
 #include <audio_effects/effect_visualizer.h>
 
 
@@ -47,9 +48,9 @@
     VISUALIZER_STATE_ACTIVE,
 };
 
-// maximum number of reads from same buffer before resetting capture buffer. This means
+// maximum time since last capture buffer update before resetting capture buffer. This means
 // that the framework has stopped playing audio and we must start returning silence
-#define MAX_STALL_COUNT 10
+#define MAX_STALL_TIME_MS 1000
 
 struct VisualizerContext {
     const struct effect_interface_s *mItfe;
@@ -59,7 +60,7 @@
     uint8_t mState;
     uint8_t mCurrentBuf;
     uint8_t mLastBuf;
-    uint8_t mStallCount;
+    struct timespec mBufferUpdateTime;
     uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
 };
 
@@ -72,7 +73,7 @@
     pContext->mCaptureIdx = 0;
     pContext->mCurrentBuf = 0;
     pContext->mLastBuf = 1;
-    pContext->mStallCount = 0;
+    pContext->mBufferUpdateTime.tv_sec = 0;
     memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
     memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
 }
@@ -321,6 +322,11 @@
     if (pContext->mCaptureIdx == pContext->mCaptureSize) {
         pContext->mCurrentBuf ^= 1;
         pContext->mCaptureIdx = 0;
+
+        // update last buffer update time stamp
+        if (clock_gettime(CLOCK_MONOTONIC, &pContext->mBufferUpdateTime) < 0) {
+            pContext->mBufferUpdateTime.tv_sec = 0;
+        }
     }
 
     if (inBuffer->raw != outBuffer->raw) {
@@ -453,16 +459,25 @@
                    pContext->mCaptureSize);
             // if audio framework has stopped playing audio although the effect is still
             // active we must clear the capture buffer to return silence
-            if (pContext->mLastBuf == pContext->mCurrentBuf) {
-                if (pContext->mStallCount < MAX_STALL_COUNT) {
-                    if (++pContext->mStallCount == MAX_STALL_COUNT) {
+            if ((pContext->mLastBuf == pContext->mCurrentBuf) &&
+                    (pContext->mBufferUpdateTime.tv_sec != 0)) {
+                struct timespec ts;
+                if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+                    time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec;
+                    long nsec = ts.tv_nsec - pContext->mBufferUpdateTime.tv_nsec;
+                    if (nsec < 0) {
+                        --secs;
+                        nsec += 1000000000;
+                    }
+                    uint32_t deltaMs = secs * 1000 + nsec / 1000000;
+                    if (deltaMs > MAX_STALL_TIME_MS) {
+                        ALOGV("capture going to idle");
+                        pContext->mBufferUpdateTime.tv_sec = 0;
                         memset(pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
                                 0x80,
                                 pContext->mCaptureSize);
                     }
                 }
-            } else {
-                pContext->mStallCount = 0;
             }
             pContext->mLastBuf = pContext->mCurrentBuf;
         } else {
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 21e8f29..c8e1dc7 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -17,6 +17,7 @@
     IAudioFlingerClient.cpp \
     IAudioTrack.cpp \
     IAudioRecord.cpp \
+    ICrypto.cpp \
     AudioRecord.cpp \
     AudioSystem.cpp \
     mediaplayer.cpp \
@@ -43,7 +44,9 @@
     IEffectClient.cpp \
     AudioEffect.cpp \
     Visualizer.cpp \
-    MemoryLeakTrackUtil.cpp
+    MemoryLeakTrackUtil.cpp \
+    SoundPool.cpp \
+    SoundPoolThread.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libui libcutils libutils libbinder libsonivox libicuuc libexpat \
@@ -55,7 +58,6 @@
 LOCAL_MODULE:= libmedia
 
 LOCAL_C_INCLUDES := \
-    $(JNI_H_INCLUDE) \
     $(call include-path-for, graphics corecg) \
     $(TOP)/frameworks/native/include/media/openmax \
     external/icu4c/common \
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 05ade75..70ec593 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -201,7 +201,7 @@
 
     // create the IAudioRecord
     status = openRecord_l(sampleRate, format, channelMask,
-                        frameCount, flags, input);
+                        frameCount, input);
     if (status != NO_ERROR) {
         return status;
     }
@@ -458,7 +458,6 @@
         audio_format_t format,
         uint32_t channelMask,
         int frameCount,
-        uint32_t flags,
         audio_io_handle_t input)
 {
     status_t status;
@@ -471,7 +470,7 @@
                                                        sampleRate, format,
                                                        channelMask,
                                                        frameCount,
-                                                       ((uint16_t)flags) << 16,
+                                                       IAudioFlinger::TRACK_DEFAULT,
                                                        &mSessionId,
                                                        &status);
 
@@ -778,7 +777,7 @@
         // following member variables: mAudioRecord, mCblkMemory and mCblk.
         // It will also delete the strong references on previous IAudioRecord and IMemory
         result = openRecord_l(cblk->sampleRate, mFormat, mChannelMask,
-                mFrameCount, mFlags, getInput_l());
+                mFrameCount, getInput_l());
         if (result == NO_ERROR) {
             result = mAudioRecord->start(0);    // callback thread hasn't changed
         }
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 50fbf36..bafde3a 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -803,16 +803,19 @@
         }
     }
 
+    IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
+    if (mIsTimed) {
+        trackFlags |= IAudioFlinger::TRACK_TIMED;
+    }
     sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
                                                       streamType,
                                                       sampleRate,
                                                       format,
                                                       channelMask,
                                                       frameCount,
-                                                      ((uint16_t)flags) << 16,
+                                                      trackFlags,
                                                       sharedBuffer,
                                                       output,
-                                                      mIsTimed,
                                                       &mSessionId,
                                                       &status);
 
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 07b12e4..ce10c8e 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -87,10 +87,9 @@
                                 audio_format_t format,
                                 uint32_t channelMask,
                                 int frameCount,
-                                uint32_t flags,
+                                track_flags_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 audio_io_handle_t output,
-                                bool isTimed,
                                 int *sessionId,
                                 status_t *status)
     {
@@ -103,10 +102,9 @@
         data.writeInt32(format);
         data.writeInt32(channelMask);
         data.writeInt32(frameCount);
-        data.writeInt32(flags);
+        data.writeInt32((int32_t) flags);
         data.writeStrongBinder(sharedBuffer->asBinder());
         data.writeInt32((int32_t) output);
-        data.writeInt32(isTimed);
         int lSessionId = 0;
         if (sessionId != NULL) {
             lSessionId = *sessionId;
@@ -136,7 +134,7 @@
                                 audio_format_t format,
                                 uint32_t channelMask,
                                 int frameCount,
-                                uint32_t flags,
+                                track_flags_t flags,
                                 int *sessionId,
                                 status_t *status)
     {
@@ -688,15 +686,14 @@
             audio_format_t format = (audio_format_t) data.readInt32();
             int channelCount = data.readInt32();
             size_t bufferCount = data.readInt32();
-            uint32_t flags = data.readInt32();
+            track_flags_t flags = (track_flags_t) data.readInt32();
             sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
             audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
-            bool isTimed = data.readInt32();
             int sessionId = data.readInt32();
             status_t status;
             sp<IAudioTrack> track = createTrack(pid,
                     (audio_stream_type_t) streamType, sampleRate, format,
-                    channelCount, bufferCount, flags, buffer, output, isTimed, &sessionId, &status);
+                    channelCount, bufferCount, flags, buffer, output, &sessionId, &status);
             reply->writeInt32(sessionId);
             reply->writeInt32(status);
             reply->writeStrongBinder(track->asBinder());
@@ -710,7 +707,7 @@
             audio_format_t format = (audio_format_t) data.readInt32();
             int channelCount = data.readInt32();
             size_t bufferCount = data.readInt32();
-            uint32_t flags = data.readInt32();
+            track_flags_t flags = (track_flags_t) data.readInt32();
             int sessionId = data.readInt32();
             status_t status;
             sp<IAudioRecord> record = openRecord(pid, input,
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
new file mode 100644
index 0000000..827d7af
--- /dev/null
+++ b/media/libmedia/ICrypto.cpp
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ICrypto"
+#include <utils/Log.h>
+
+#include <binder/Parcel.h>
+#include <media/ICrypto.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+enum {
+    INITIALIZE = IBinder::FIRST_CALL_TRANSACTION,
+    TERMINATE,
+    SET_ENTITLEMENT_KEY,
+    SET_ECM,
+    DECRYPT_VIDEO,
+    DECRYPT_AUDIO,
+};
+
+struct BpCrypto : public BpInterface<ICrypto> {
+    BpCrypto(const sp<IBinder> &impl)
+        : BpInterface<ICrypto>(impl) {
+    }
+
+    virtual status_t initialize() {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+        remote()->transact(INITIALIZE, data, &reply);
+
+        return reply.readInt32();
+    }
+
+    virtual status_t terminate() {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+        remote()->transact(TERMINATE, data, &reply);
+
+        return reply.readInt32();
+    }
+
+    virtual status_t setEntitlementKey(
+            const void *key, size_t keyLength) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+        data.writeInt32(keyLength);
+        data.write(key, keyLength);
+        remote()->transact(SET_ENTITLEMENT_KEY, data, &reply);
+
+        return reply.readInt32();
+    }
+
+    virtual status_t setEntitlementControlMessage(
+            const void *msg, size_t msgLength) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+        data.writeInt32(msgLength);
+        data.write(msg, msgLength);
+        remote()->transact(SET_ECM, data, &reply);
+
+        return reply.readInt32();
+    }
+
+    virtual ssize_t decryptVideo(
+            const void *iv, size_t ivLength,
+            const void *srcData, size_t srcDataSize,
+            void *dstData, size_t dstDataOffset) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+        if (iv == NULL) {
+            if (ivLength > 0) {
+                return -EINVAL;
+            }
+
+            data.writeInt32(-1);
+        } else {
+            data.writeInt32(ivLength);
+            data.write(iv, ivLength);
+        }
+
+        data.writeInt32(srcDataSize);
+        data.write(srcData, srcDataSize);
+
+        data.writeIntPtr((intptr_t)dstData);
+        data.writeInt32(dstDataOffset);
+
+        remote()->transact(DECRYPT_VIDEO, data, &reply);
+
+        return reply.readInt32();
+    }
+
+    virtual ssize_t decryptAudio(
+            const void *iv, size_t ivLength,
+            const void *srcData, size_t srcDataSize,
+            void *dstData, size_t dstDataSize) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+        if (iv == NULL) {
+            if (ivLength > 0) {
+                return -EINVAL;
+            }
+
+            data.writeInt32(-1);
+        } else {
+            data.writeInt32(ivLength);
+            data.write(iv, ivLength);
+        }
+
+        data.writeInt32(srcDataSize);
+        data.write(srcData, srcDataSize);
+        data.writeInt32(dstDataSize);
+
+        remote()->transact(DECRYPT_AUDIO, data, &reply);
+
+        ssize_t res = reply.readInt32();
+
+        if (res <= 0) {
+            return res;
+        }
+
+        reply.read(dstData, res);
+
+        return res;
+    }
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(BpCrypto);
+};
+
+IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
+
+////////////////////////////////////////////////////////////////////////////////
+
+status_t BnCrypto::onTransact(
+    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+    switch (code) {
+        case INITIALIZE:
+        {
+            CHECK_INTERFACE(ICrypto, data, reply);
+            reply->writeInt32(initialize());
+
+            return OK;
+        }
+
+        case TERMINATE:
+        {
+            CHECK_INTERFACE(ICrypto, data, reply);
+            reply->writeInt32(terminate());
+
+            return OK;
+        }
+
+        case SET_ENTITLEMENT_KEY:
+        {
+            CHECK_INTERFACE(ICrypto, data, reply);
+
+            size_t keyLength = data.readInt32();
+            void *key = malloc(keyLength);
+            data.read(key, keyLength);
+
+            reply->writeInt32(setEntitlementKey(key, keyLength));
+
+            free(key);
+            key = NULL;
+
+            return OK;
+        }
+
+        case SET_ECM:
+        {
+            CHECK_INTERFACE(ICrypto, data, reply);
+
+            size_t msgLength = data.readInt32();
+            void *msg = malloc(msgLength);
+            data.read(msg, msgLength);
+
+            reply->writeInt32(setEntitlementControlMessage(msg, msgLength));
+
+            free(msg);
+            msg = NULL;
+
+            return OK;
+        }
+
+        case DECRYPT_VIDEO:
+        {
+            CHECK_INTERFACE(ICrypto, data, reply);
+
+            void *iv = NULL;
+
+            int32_t ivLength = data.readInt32();
+            if (ivLength >= 0) {
+                iv = malloc(ivLength);
+                data.read(iv, ivLength);
+            }
+
+            size_t srcDataSize = data.readInt32();
+            void *srcData = malloc(srcDataSize);
+            data.read(srcData, srcDataSize);
+
+            void *dstData = (void *)data.readIntPtr();
+            size_t dstDataOffset = data.readInt32();
+
+            reply->writeInt32(
+                    decryptVideo(
+                        iv,
+                        ivLength < 0 ? 0 : ivLength,
+                        srcData,
+                        srcDataSize,
+                        dstData,
+                        dstDataOffset));
+
+            free(srcData);
+            srcData = NULL;
+
+            if (iv != NULL) {
+                free(iv);
+                iv = NULL;
+            }
+
+            return OK;
+        }
+
+        case DECRYPT_AUDIO:
+        {
+            CHECK_INTERFACE(ICrypto, data, reply);
+
+            void *iv = NULL;
+
+            int32_t ivLength = data.readInt32();
+            if (ivLength >= 0) {
+                iv = malloc(ivLength);
+                data.read(iv, ivLength);
+            }
+
+            size_t srcDataSize = data.readInt32();
+            void *srcData = malloc(srcDataSize);
+            data.read(srcData, srcDataSize);
+
+            size_t dstDataSize = data.readInt32();
+            void *dstData = malloc(dstDataSize);
+
+            ssize_t res =
+                decryptAudio(
+                        iv,
+                        ivLength < 0 ? 0 : ivLength,
+                        srcData,
+                        srcDataSize,
+                        dstData,
+                        dstDataSize);
+
+            reply->writeInt32(res);
+
+            if (res > 0) {
+                reply->write(dstData, res);
+            }
+
+            free(dstData);
+            dstData = NULL;
+
+            free(srcData);
+            srcData = NULL;
+
+            if (iv != NULL) {
+                free(iv);
+                iv = NULL;
+            }
+
+            return OK;
+        }
+
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}  // namespace android
+
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 9b8d7c3..7e6d54b 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -18,7 +18,6 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <binder/Parcel.h>
-#include <SkBitmap.h>
 #include <media/IMediaMetadataRetriever.h>
 #include <utils/String8.h>
 
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index f5fccef..9120617 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -20,6 +20,7 @@
 
 #include <binder/Parcel.h>
 #include <binder/IMemory.h>
+#include <media/ICrypto.h>
 #include <media/IMediaPlayerService.h>
 #include <media/IMediaRecorder.h>
 #include <media/IOMX.h>
@@ -36,6 +37,7 @@
     CREATE_MEDIA_RECORDER,
     CREATE_METADATA_RETRIEVER,
     GET_OMX,
+    MAKE_CRYPTO,
     ADD_BATTERY_DATA,
     PULL_BATTERY_DATA
 };
@@ -111,6 +113,13 @@
         return interface_cast<IOMX>(reply.readStrongBinder());
     }
 
+    virtual sp<ICrypto> makeCrypto() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+        remote()->transact(MAKE_CRYPTO, data, &reply);
+        return interface_cast<ICrypto>(reply.readStrongBinder());
+    }
+
     virtual void addBatteryData(uint32_t params) {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
@@ -191,6 +200,12 @@
             reply->writeStrongBinder(omx->asBinder());
             return NO_ERROR;
         } break;
+        case MAKE_CRYPTO: {
+            CHECK_INTERFACE(IMediaPlayerService, data, reply);
+            sp<ICrypto> crypto = makeCrypto();
+            reply->writeStrongBinder(crypto->asBinder());
+            return NO_ERROR;
+        } break;
         case ADD_BATTERY_DATA: {
             CHECK_INTERFACE(IMediaPlayerService, data, reply);
             uint32_t params = data.readInt32();
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 7fa6bb7..52aee49 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -30,7 +30,7 @@
 static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
 
 //-------------------------------------------------------------------------------------------------
-JetPlayer::JetPlayer(jobject javaJetPlayer, int maxTracks, int trackBufferSize) :
+JetPlayer::JetPlayer(void *javaJetPlayer, int maxTracks, int trackBufferSize) :
         mEventCallback(NULL),
         mJavaJetPlayerRef(javaJetPlayer),
         mTid(-1),
diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp
new file mode 100644
index 0000000..306c57d
--- /dev/null
+++ b/media/libmedia/SoundPool.cpp
@@ -0,0 +1,908 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoundPool"
+#include <utils/Log.h>
+
+//#define USE_SHARED_MEM_BUFFER
+
+// XXX needed for timing latency
+#include <utils/Timers.h>
+
+#include <media/AudioTrack.h>
+#include <media/mediaplayer.h>
+
+#include <system/audio.h>
+
+#include "SoundPool.h"
+#include "SoundPoolThread.h"
+
+namespace android
+{
+
+int kDefaultBufferCount = 4;
+uint32_t kMaxSampleRate = 48000;
+uint32_t kDefaultSampleRate = 44100;
+uint32_t kDefaultFrameCount = 1200;
+
+SoundPool::SoundPool(int maxChannels, audio_stream_type_t streamType, int srcQuality)
+{
+    ALOGV("SoundPool constructor: maxChannels=%d, streamType=%d, srcQuality=%d",
+            maxChannels, streamType, srcQuality);
+
+    // check limits
+    mMaxChannels = maxChannels;
+    if (mMaxChannels < 1) {
+        mMaxChannels = 1;
+    }
+    else if (mMaxChannels > 32) {
+        mMaxChannels = 32;
+    }
+    ALOGW_IF(maxChannels != mMaxChannels, "App requested %d channels", maxChannels);
+
+    mQuit = false;
+    mDecodeThread = 0;
+    mStreamType = streamType;
+    mSrcQuality = srcQuality;
+    mAllocated = 0;
+    mNextSampleID = 0;
+    mNextChannelID = 0;
+
+    mCallback = 0;
+    mUserData = 0;
+
+    mChannelPool = new SoundChannel[mMaxChannels];
+    for (int i = 0; i < mMaxChannels; ++i) {
+        mChannelPool[i].init(this);
+        mChannels.push_back(&mChannelPool[i]);
+    }
+
+    // start decode thread
+    startThreads();
+}
+
+SoundPool::~SoundPool()
+{
+    ALOGV("SoundPool destructor");
+    mDecodeThread->quit();
+    quit();
+
+    Mutex::Autolock lock(&mLock);
+
+    mChannels.clear();
+    if (mChannelPool)
+        delete [] mChannelPool;
+    // clean up samples
+    ALOGV("clear samples");
+    mSamples.clear();
+
+    if (mDecodeThread)
+        delete mDecodeThread;
+}
+
+void SoundPool::addToRestartList(SoundChannel* channel)
+{
+    Mutex::Autolock lock(&mRestartLock);
+    if (!mQuit) {
+        mRestart.push_back(channel);
+        mCondition.signal();
+    }
+}
+
+void SoundPool::addToStopList(SoundChannel* channel)
+{
+    Mutex::Autolock lock(&mRestartLock);
+    if (!mQuit) {
+        mStop.push_back(channel);
+        mCondition.signal();
+    }
+}
+
+int SoundPool::beginThread(void* arg)
+{
+    SoundPool* p = (SoundPool*)arg;
+    return p->run();
+}
+
+int SoundPool::run()
+{
+    mRestartLock.lock();
+    while (!mQuit) {
+        mCondition.wait(mRestartLock);
+        ALOGV("awake");
+        if (mQuit) break;
+
+        while (!mStop.empty()) {
+            SoundChannel* channel;
+            ALOGV("Getting channel from stop list");
+            List<SoundChannel* >::iterator iter = mStop.begin();
+            channel = *iter;
+            mStop.erase(iter);
+            mRestartLock.unlock();
+            if (channel != 0) {
+                Mutex::Autolock lock(&mLock);
+                channel->stop();
+            }
+            mRestartLock.lock();
+            if (mQuit) break;
+        }
+
+        while (!mRestart.empty()) {
+            SoundChannel* channel;
+            ALOGV("Getting channel from list");
+            List<SoundChannel*>::iterator iter = mRestart.begin();
+            channel = *iter;
+            mRestart.erase(iter);
+            mRestartLock.unlock();
+            if (channel != 0) {
+                Mutex::Autolock lock(&mLock);
+                channel->nextEvent();
+            }
+            mRestartLock.lock();
+            if (mQuit) break;
+        }
+    }
+
+    mStop.clear();
+    mRestart.clear();
+    mCondition.signal();
+    mRestartLock.unlock();
+    ALOGV("goodbye");
+    return 0;
+}
+
+void SoundPool::quit()
+{
+    mRestartLock.lock();
+    mQuit = true;
+    mCondition.signal();
+    mCondition.wait(mRestartLock);
+    ALOGV("return from quit");
+    mRestartLock.unlock();
+}
+
+bool SoundPool::startThreads()
+{
+    createThreadEtc(beginThread, this, "SoundPool");
+    if (mDecodeThread == NULL)
+        mDecodeThread = new SoundPoolThread(this);
+    return mDecodeThread != NULL;
+}
+
+SoundChannel* SoundPool::findChannel(int channelID)
+{
+    for (int i = 0; i < mMaxChannels; ++i) {
+        if (mChannelPool[i].channelID() == channelID) {
+            return &mChannelPool[i];
+        }
+    }
+    return NULL;
+}
+
+SoundChannel* SoundPool::findNextChannel(int channelID)
+{
+    for (int i = 0; i < mMaxChannels; ++i) {
+        if (mChannelPool[i].nextChannelID() == channelID) {
+            return &mChannelPool[i];
+        }
+    }
+    return NULL;
+}
+
+int SoundPool::load(const char* path, int priority)
+{
+    ALOGV("load: path=%s, priority=%d", path, priority);
+    Mutex::Autolock lock(&mLock);
+    sp<Sample> sample = new Sample(++mNextSampleID, path);
+    mSamples.add(sample->sampleID(), sample);
+    doLoad(sample);
+    return sample->sampleID();
+}
+
+int SoundPool::load(int fd, int64_t offset, int64_t length, int priority)
+{
+    ALOGV("load: fd=%d, offset=%lld, length=%lld, priority=%d",
+            fd, offset, length, priority);
+    Mutex::Autolock lock(&mLock);
+    sp<Sample> sample = new Sample(++mNextSampleID, fd, offset, length);
+    mSamples.add(sample->sampleID(), sample);
+    doLoad(sample);
+    return sample->sampleID();
+}
+
+void SoundPool::doLoad(sp<Sample>& sample)
+{
+    ALOGV("doLoad: loading sample sampleID=%d", sample->sampleID());
+    sample->startLoad();
+    mDecodeThread->loadSample(sample->sampleID());
+}
+
+bool SoundPool::unload(int sampleID)
+{
+    ALOGV("unload: sampleID=%d", sampleID);
+    Mutex::Autolock lock(&mLock);
+    return mSamples.removeItem(sampleID);
+}
+
+int SoundPool::play(int sampleID, float leftVolume, float rightVolume,
+        int priority, int loop, float rate)
+{
+    ALOGV("play sampleID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f",
+            sampleID, leftVolume, rightVolume, priority, loop, rate);
+    sp<Sample> sample;
+    SoundChannel* channel;
+    int channelID;
+
+    Mutex::Autolock lock(&mLock);
+
+    if (mQuit) {
+        return 0;
+    }
+    // is sample ready?
+    sample = findSample(sampleID);
+    if ((sample == 0) || (sample->state() != Sample::READY)) {
+        ALOGW("  sample %d not READY", sampleID);
+        return 0;
+    }
+
+    dump();
+
+    // allocate a channel
+    channel = allocateChannel_l(priority);
+
+    // no channel allocated - return 0
+    if (!channel) {
+        ALOGV("No channel allocated");
+        return 0;
+    }
+
+    channelID = ++mNextChannelID;
+
+    ALOGV("play channel %p state = %d", channel, channel->state());
+    channel->play(sample, channelID, leftVolume, rightVolume, priority, loop, rate);
+    return channelID;
+}
+
+SoundChannel* SoundPool::allocateChannel_l(int priority)
+{
+    List<SoundChannel*>::iterator iter;
+    SoundChannel* channel = NULL;
+
+    // allocate a channel
+    if (!mChannels.empty()) {
+        iter = mChannels.begin();
+        if (priority >= (*iter)->priority()) {
+            channel = *iter;
+            mChannels.erase(iter);
+            ALOGV("Allocated active channel");
+        }
+    }
+
+    // update priority and put it back in the list
+    if (channel) {
+        channel->setPriority(priority);
+        for (iter = mChannels.begin(); iter != mChannels.end(); ++iter) {
+            if (priority < (*iter)->priority()) {
+                break;
+            }
+        }
+        mChannels.insert(iter, channel);
+    }
+    return channel;
+}
+
+// move a channel from its current position to the front of the list
+void SoundPool::moveToFront_l(SoundChannel* channel)
+{
+    for (List<SoundChannel*>::iterator iter = mChannels.begin(); iter != mChannels.end(); ++iter) {
+        if (*iter == channel) {
+            mChannels.erase(iter);
+            mChannels.push_front(channel);
+            break;
+        }
+    }
+}
+
+void SoundPool::pause(int channelID)
+{
+    ALOGV("pause(%d)", channelID);
+    Mutex::Autolock lock(&mLock);
+    SoundChannel* channel = findChannel(channelID);
+    if (channel) {
+        channel->pause();
+    }
+}
+
+void SoundPool::autoPause()
+{
+    ALOGV("autoPause()");
+    Mutex::Autolock lock(&mLock);
+    for (int i = 0; i < mMaxChannels; ++i) {
+        SoundChannel* channel = &mChannelPool[i];
+        channel->autoPause();
+    }
+}
+
+void SoundPool::resume(int channelID)
+{
+    ALOGV("resume(%d)", channelID);
+    Mutex::Autolock lock(&mLock);
+    SoundChannel* channel = findChannel(channelID);
+    if (channel) {
+        channel->resume();
+    }
+}
+
+void SoundPool::autoResume()
+{
+    ALOGV("autoResume()");
+    Mutex::Autolock lock(&mLock);
+    for (int i = 0; i < mMaxChannels; ++i) {
+        SoundChannel* channel = &mChannelPool[i];
+        channel->autoResume();
+    }
+}
+
+void SoundPool::stop(int channelID)
+{
+    ALOGV("stop(%d)", channelID);
+    Mutex::Autolock lock(&mLock);
+    SoundChannel* channel = findChannel(channelID);
+    if (channel) {
+        channel->stop();
+    } else {
+        channel = findNextChannel(channelID);
+        if (channel)
+            channel->clearNextEvent();
+    }
+}
+
+void SoundPool::setVolume(int channelID, float leftVolume, float rightVolume)
+{
+    Mutex::Autolock lock(&mLock);
+    SoundChannel* channel = findChannel(channelID);
+    if (channel) {
+        channel->setVolume(leftVolume, rightVolume);
+    }
+}
+
+void SoundPool::setPriority(int channelID, int priority)
+{
+    ALOGV("setPriority(%d, %d)", channelID, priority);
+    Mutex::Autolock lock(&mLock);
+    SoundChannel* channel = findChannel(channelID);
+    if (channel) {
+        channel->setPriority(priority);
+    }
+}
+
+void SoundPool::setLoop(int channelID, int loop)
+{
+    ALOGV("setLoop(%d, %d)", channelID, loop);
+    Mutex::Autolock lock(&mLock);
+    SoundChannel* channel = findChannel(channelID);
+    if (channel) {
+        channel->setLoop(loop);
+    }
+}
+
+void SoundPool::setRate(int channelID, float rate)
+{
+    ALOGV("setRate(%d, %f)", channelID, rate);
+    Mutex::Autolock lock(&mLock);
+    SoundChannel* channel = findChannel(channelID);
+    if (channel) {
+        channel->setRate(rate);
+    }
+}
+
+// call with lock held
+void SoundPool::done_l(SoundChannel* channel)
+{
+    ALOGV("done_l(%d)", channel->channelID());
+    // if "stolen", play next event
+    if (channel->nextChannelID() != 0) {
+        ALOGV("add to restart list");
+        addToRestartList(channel);
+    }
+
+    // return to idle state
+    else {
+        ALOGV("move to front");
+        moveToFront_l(channel);
+    }
+}
+
+void SoundPool::setCallback(SoundPoolCallback* callback, void* user)
+{
+    Mutex::Autolock lock(&mCallbackLock);
+    mCallback = callback;
+    mUserData = user;
+}
+
+void SoundPool::notify(SoundPoolEvent event)
+{
+    Mutex::Autolock lock(&mCallbackLock);
+    if (mCallback != NULL) {
+        mCallback(event, this, mUserData);
+    }
+}
+
+void SoundPool::dump()
+{
+    for (int i = 0; i < mMaxChannels; ++i) {
+        mChannelPool[i].dump();
+    }
+}
+
+
+Sample::Sample(int sampleID, const char* url)
+{
+    init();
+    mSampleID = sampleID;
+    mUrl = strdup(url);
+    ALOGV("create sampleID=%d, url=%s", mSampleID, mUrl);
+}
+
+Sample::Sample(int sampleID, int fd, int64_t offset, int64_t length)
+{
+    init();
+    mSampleID = sampleID;
+    mFd = dup(fd);
+    mOffset = offset;
+    mLength = length;
+    ALOGV("create sampleID=%d, fd=%d, offset=%lld, length=%lld", mSampleID, mFd, mLength, mOffset);
+}
+
+void Sample::init()
+{
+    mData = 0;
+    mSize = 0;
+    mRefCount = 0;
+    mSampleID = 0;
+    mState = UNLOADED;
+    mFd = -1;
+    mOffset = 0;
+    mLength = 0;
+    mUrl = 0;
+}
+
+Sample::~Sample()
+{
+    ALOGV("Sample::destructor sampleID=%d, fd=%d", mSampleID, mFd);
+    if (mFd > 0) {
+        ALOGV("close(%d)", mFd);
+        ::close(mFd);
+    }
+    mData.clear();
+    delete mUrl;
+}
+
+status_t Sample::doLoad()
+{
+    uint32_t sampleRate;
+    int numChannels;
+    audio_format_t format;
+    sp<IMemory> p;
+    ALOGV("Start decode");
+    if (mUrl) {
+        p = MediaPlayer::decode(mUrl, &sampleRate, &numChannels, &format);
+    } else {
+        p = MediaPlayer::decode(mFd, mOffset, mLength, &sampleRate, &numChannels, &format);
+        ALOGV("close(%d)", mFd);
+        ::close(mFd);
+        mFd = -1;
+    }
+    if (p == 0) {
+        ALOGE("Unable to load sample: %s", mUrl);
+        return -1;
+    }
+    ALOGV("pointer = %p, size = %u, sampleRate = %u, numChannels = %d",
+            p->pointer(), p->size(), sampleRate, numChannels);
+
+    if (sampleRate > kMaxSampleRate) {
+       ALOGE("Sample rate (%u) out of range", sampleRate);
+       return - 1;
+    }
+
+    if ((numChannels < 1) || (numChannels > 2)) {
+        ALOGE("Sample channel count (%d) out of range", numChannels);
+        return - 1;
+    }
+
+    //_dumpBuffer(p->pointer(), p->size());
+    uint8_t* q = static_cast<uint8_t*>(p->pointer()) + p->size() - 10;
+    //_dumpBuffer(q, 10, 10, false);
+
+    mData = p;
+    mSize = p->size();
+    mSampleRate = sampleRate;
+    mNumChannels = numChannels;
+    mFormat = format;
+    mState = READY;
+    return 0;
+}
+
+
+void SoundChannel::init(SoundPool* soundPool)
+{
+    mSoundPool = soundPool;
+}
+
+// call with sound pool lock held
+void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftVolume,
+        float rightVolume, int priority, int loop, float rate)
+{
+    AudioTrack* oldTrack;
+    AudioTrack* newTrack;
+    status_t status;
+
+    { // scope for the lock
+        Mutex::Autolock lock(&mLock);
+
+        ALOGV("SoundChannel::play %p: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f,"
+                " priority=%d, loop=%d, rate=%f",
+                this, sample->sampleID(), nextChannelID, leftVolume, rightVolume,
+                priority, loop, rate);
+
+        // if not idle, this voice is being stolen
+        if (mState != IDLE) {
+            ALOGV("channel %d stolen - event queued for channel %d", channelID(), nextChannelID);
+            mNextEvent.set(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
+            stop_l();
+            return;
+        }
+
+        // initialize track
+        int afFrameCount;
+        int afSampleRate;
+        audio_stream_type_t streamType = mSoundPool->streamType();
+        if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
+            afFrameCount = kDefaultFrameCount;
+        }
+        if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
+            afSampleRate = kDefaultSampleRate;
+        }
+        int numChannels = sample->numChannels();
+        uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5);
+        uint32_t totalFrames = (kDefaultBufferCount * afFrameCount * sampleRate) / afSampleRate;
+        uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount;
+        uint32_t frameCount = 0;
+
+        if (loop) {
+            frameCount = sample->size()/numChannels/
+                ((sample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
+        }
+
+#ifndef USE_SHARED_MEM_BUFFER
+        // Ensure minimum audio buffer size in case of short looped sample
+        if(frameCount < totalFrames) {
+            frameCount = totalFrames;
+        }
+#endif
+
+        // mToggle toggles each time a track is started on a given channel.
+        // The toggle is concatenated with the SoundChannel address and passed to AudioTrack
+        // as callback user data. This enables the detection of callbacks received from the old
+        // audio track while the new one is being started and avoids processing them with
+        // wrong audio audio buffer size  (mAudioBufferSize)
+        unsigned long toggle = mToggle ^ 1;
+        void *userData = (void *)((unsigned long)this | toggle);
+        uint32_t channels = (numChannels == 2) ?
+                AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO;
+
+        // do not create a new audio track if current track is compatible with sample parameters
+#ifdef USE_SHARED_MEM_BUFFER
+        newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
+                channels, sample->getIMemory(), AUDIO_POLICY_OUTPUT_FLAG_NONE, callback, userData);
+#else
+        newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
+                channels, frameCount, AUDIO_POLICY_OUTPUT_FLAG_NONE, callback, userData,
+                bufferFrames);
+#endif
+        oldTrack = mAudioTrack;
+        status = newTrack->initCheck();
+        if (status != NO_ERROR) {
+            ALOGE("Error creating AudioTrack");
+            goto exit;
+        }
+        ALOGV("setVolume %p", newTrack);
+        newTrack->setVolume(leftVolume, rightVolume);
+        newTrack->setLoop(0, frameCount, loop);
+
+        // From now on, AudioTrack callbacks received with previous toggle value will be ignored.
+        mToggle = toggle;
+        mAudioTrack = newTrack;
+        mPos = 0;
+        mSample = sample;
+        mChannelID = nextChannelID;
+        mPriority = priority;
+        mLoop = loop;
+        mLeftVolume = leftVolume;
+        mRightVolume = rightVolume;
+        mNumChannels = numChannels;
+        mRate = rate;
+        clearNextEvent();
+        mState = PLAYING;
+        mAudioTrack->start();
+        mAudioBufferSize = newTrack->frameCount()*newTrack->frameSize();
+    }
+
+exit:
+    ALOGV("delete oldTrack %p", oldTrack);
+    delete oldTrack;
+    if (status != NO_ERROR) {
+        delete newTrack;
+        mAudioTrack = NULL;
+    }
+}
+
+void SoundChannel::nextEvent()
+{
+    sp<Sample> sample;
+    int nextChannelID;
+    float leftVolume;
+    float rightVolume;
+    int priority;
+    int loop;
+    float rate;
+
+    // check for valid event
+    {
+        Mutex::Autolock lock(&mLock);
+        nextChannelID = mNextEvent.channelID();
+        if (nextChannelID  == 0) {
+            ALOGV("stolen channel has no event");
+            return;
+        }
+
+        sample = mNextEvent.sample();
+        leftVolume = mNextEvent.leftVolume();
+        rightVolume = mNextEvent.rightVolume();
+        priority = mNextEvent.priority();
+        loop = mNextEvent.loop();
+        rate = mNextEvent.rate();
+    }
+
+    ALOGV("Starting stolen channel %d -> %d", channelID(), nextChannelID);
+    play(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
+}
+
+void SoundChannel::callback(int event, void* user, void *info)
+{
+    SoundChannel* channel = static_cast<SoundChannel*>((void *)((unsigned long)user & ~1));
+
+    channel->process(event, info, (unsigned long)user & 1);
+}
+
+void SoundChannel::process(int event, void *info, unsigned long toggle)
+{
+    //ALOGV("process(%d)", mChannelID);
+
+    Mutex::Autolock lock(&mLock);
+
+    AudioTrack::Buffer* b = NULL;
+    if (event == AudioTrack::EVENT_MORE_DATA) {
+       b = static_cast<AudioTrack::Buffer *>(info);
+    }
+
+    if (mToggle != toggle) {
+        ALOGV("process wrong toggle %p channel %d", this, mChannelID);
+        if (b != NULL) {
+            b->size = 0;
+        }
+        return;
+    }
+
+    sp<Sample> sample = mSample;
+
+//    ALOGV("SoundChannel::process event %d", event);
+
+    if (event == AudioTrack::EVENT_MORE_DATA) {
+
+        // check for stop state
+        if (b->size == 0) return;
+
+        if (mState == IDLE) {
+            b->size = 0;
+            return;
+        }
+
+        if (sample != 0) {
+            // fill buffer
+            uint8_t* q = (uint8_t*) b->i8;
+            size_t count = 0;
+
+            if (mPos < (int)sample->size()) {
+                uint8_t* p = sample->data() + mPos;
+                count = sample->size() - mPos;
+                if (count > b->size) {
+                    count = b->size;
+                }
+                memcpy(q, p, count);
+//              ALOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size, count);
+            } else if (mPos < mAudioBufferSize) {
+                count = mAudioBufferSize - mPos;
+                if (count > b->size) {
+                    count = b->size;
+                }
+                memset(q, 0, count);
+//              ALOGV("fill extra: q=%p, mPos=%u, b->size=%u, count=%d", q, mPos, b->size, count);
+            }
+
+            mPos += count;
+            b->size = count;
+            //ALOGV("buffer=%p, [0]=%d", b->i16, b->i16[0]);
+        }
+    } else if (event == AudioTrack::EVENT_UNDERRUN) {
+        ALOGV("process %p channel %d EVENT_UNDERRUN", this, mChannelID);
+        mSoundPool->addToStopList(this);
+    } else if (event == AudioTrack::EVENT_LOOP_END) {
+        ALOGV("End loop %p channel %d count %d", this, mChannelID, *(int *)info);
+    }
+}
+
+
+// call with lock held
+bool SoundChannel::doStop_l()
+{
+    if (mState != IDLE) {
+        setVolume_l(0, 0);
+        ALOGV("stop");
+        mAudioTrack->stop();
+        mSample.clear();
+        mState = IDLE;
+        mPriority = IDLE_PRIORITY;
+        return true;
+    }
+    return false;
+}
+
+// call with lock held and sound pool lock held
+void SoundChannel::stop_l()
+{
+    if (doStop_l()) {
+        mSoundPool->done_l(this);
+    }
+}
+
+// call with sound pool lock held
+void SoundChannel::stop()
+{
+    bool stopped;
+    {
+        Mutex::Autolock lock(&mLock);
+        stopped = doStop_l();
+    }
+
+    if (stopped) {
+        mSoundPool->done_l(this);
+    }
+}
+
+//FIXME: Pause is a little broken right now
+void SoundChannel::pause()
+{
+    Mutex::Autolock lock(&mLock);
+    if (mState == PLAYING) {
+        ALOGV("pause track");
+        mState = PAUSED;
+        mAudioTrack->pause();
+    }
+}
+
+void SoundChannel::autoPause()
+{
+    Mutex::Autolock lock(&mLock);
+    if (mState == PLAYING) {
+        ALOGV("pause track");
+        mState = PAUSED;
+        mAutoPaused = true;
+        mAudioTrack->pause();
+    }
+}
+
+void SoundChannel::resume()
+{
+    Mutex::Autolock lock(&mLock);
+    if (mState == PAUSED) {
+        ALOGV("resume track");
+        mState = PLAYING;
+        mAutoPaused = false;
+        mAudioTrack->start();
+    }
+}
+
+void SoundChannel::autoResume()
+{
+    Mutex::Autolock lock(&mLock);
+    if (mAutoPaused && (mState == PAUSED)) {
+        ALOGV("resume track");
+        mState = PLAYING;
+        mAutoPaused = false;
+        mAudioTrack->start();
+    }
+}
+
+void SoundChannel::setRate(float rate)
+{
+    Mutex::Autolock lock(&mLock);
+    if (mAudioTrack != NULL && mSample != 0) {
+        uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5);
+        mAudioTrack->setSampleRate(sampleRate);
+        mRate = rate;
+    }
+}
+
+// call with lock held
+void SoundChannel::setVolume_l(float leftVolume, float rightVolume)
+{
+    mLeftVolume = leftVolume;
+    mRightVolume = rightVolume;
+    if (mAudioTrack != NULL)
+        mAudioTrack->setVolume(leftVolume, rightVolume);
+}
+
+void SoundChannel::setVolume(float leftVolume, float rightVolume)
+{
+    Mutex::Autolock lock(&mLock);
+    setVolume_l(leftVolume, rightVolume);
+}
+
+void SoundChannel::setLoop(int loop)
+{
+    Mutex::Autolock lock(&mLock);
+    if (mAudioTrack != NULL && mSample != 0) {
+        uint32_t loopEnd = mSample->size()/mNumChannels/
+            ((mSample->format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
+        mAudioTrack->setLoop(0, loopEnd, loop);
+        mLoop = loop;
+    }
+}
+
+SoundChannel::~SoundChannel()
+{
+    ALOGV("SoundChannel destructor %p", this);
+    {
+        Mutex::Autolock lock(&mLock);
+        clearNextEvent();
+        doStop_l();
+    }
+    // do not call AudioTrack destructor with mLock held as it will wait for the AudioTrack
+    // callback thread to exit which may need to execute process() and acquire the mLock.
+    delete mAudioTrack;
+}
+
+void SoundChannel::dump()
+{
+    ALOGV("mState = %d mChannelID=%d, mNumChannels=%d, mPos = %d, mPriority=%d, mLoop=%d",
+            mState, mChannelID, mNumChannels, mPos, mPriority, mLoop);
+}
+
+void SoundEvent::set(const sp<Sample>& sample, int channelID, float leftVolume,
+            float rightVolume, int priority, int loop, float rate)
+{
+    mSample = sample;
+    mChannelID = channelID;
+    mLeftVolume = leftVolume;
+    mRightVolume = rightVolume;
+    mPriority = priority;
+    mLoop = loop;
+    mRate =rate;
+}
+
+} // end namespace android
diff --git a/media/libmedia/SoundPool.h b/media/libmedia/SoundPool.h
new file mode 100644
index 0000000..002b045
--- /dev/null
+++ b/media/libmedia/SoundPool.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOUNDPOOL_H_
+#define SOUNDPOOL_H_
+
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
+#include <media/AudioTrack.h>
+
+namespace android {
+
+static const int IDLE_PRIORITY = -1;
+
+// forward declarations
+class SoundEvent;
+class SoundPoolThread;
+class SoundPool;
+
+// for queued events
+class SoundPoolEvent {
+public:
+    SoundPoolEvent(int msg, int arg1=0, int arg2=0) :
+        mMsg(msg), mArg1(arg1), mArg2(arg2) {}
+    int         mMsg;
+    int         mArg1;
+    int         mArg2;
+    enum MessageType { INVALID, SAMPLE_LOADED };
+};
+
+// callback function prototype
+typedef void SoundPoolCallback(SoundPoolEvent event, SoundPool* soundPool, void* user);
+
+// tracks samples used by application
+class Sample  : public RefBase {
+public:
+    enum sample_state { UNLOADED, LOADING, READY, UNLOADING };
+    Sample(int sampleID, const char* url);
+    Sample(int sampleID, int fd, int64_t offset, int64_t length);
+    ~Sample();
+    int sampleID() { return mSampleID; }
+    int numChannels() { return mNumChannels; }
+    int sampleRate() { return mSampleRate; }
+    audio_format_t format() { return mFormat; }
+    size_t size() { return mSize; }
+    int state() { return mState; }
+    uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); }
+    status_t doLoad();
+    void startLoad() { mState = LOADING; }
+    sp<IMemory> getIMemory() { return mData; }
+
+    // hack
+    void init(int numChannels, int sampleRate, audio_format_t format, size_t size, sp<IMemory> data ) {
+        mNumChannels = numChannels; mSampleRate = sampleRate; mFormat = format; mSize = size; mData = data; }
+
+private:
+    void init();
+
+    size_t              mSize;
+    volatile int32_t    mRefCount;
+    uint16_t            mSampleID;
+    uint16_t            mSampleRate;
+    uint8_t             mState : 3;
+    uint8_t             mNumChannels : 2;
+    audio_format_t      mFormat;
+    int                 mFd;
+    int64_t             mOffset;
+    int64_t             mLength;
+    char*               mUrl;
+    sp<IMemory>         mData;
+};
+
+// stores pending events for stolen channels
+class SoundEvent
+{
+public:
+    SoundEvent() : mChannelID(0), mLeftVolume(0), mRightVolume(0),
+            mPriority(IDLE_PRIORITY), mLoop(0), mRate(0) {}
+    void set(const sp<Sample>& sample, int channelID, float leftVolume,
+            float rightVolume, int priority, int loop, float rate);
+    sp<Sample>      sample() { return mSample; }
+    int             channelID() { return mChannelID; }
+    float           leftVolume() { return mLeftVolume; }
+    float           rightVolume() { return mRightVolume; }
+    int             priority() { return mPriority; }
+    int             loop() { return mLoop; }
+    float           rate() { return mRate; }
+    void            clear() { mChannelID = 0; mSample.clear(); }
+
+protected:
+    sp<Sample>      mSample;
+    int             mChannelID;
+    float           mLeftVolume;
+    float           mRightVolume;
+    int             mPriority;
+    int             mLoop;
+    float           mRate;
+};
+
+// for channels aka AudioTracks
+class SoundChannel : public SoundEvent {
+public:
+    enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
+    SoundChannel() : mAudioTrack(NULL), mState(IDLE), mNumChannels(1),
+            mPos(0), mToggle(0), mAutoPaused(false) {}
+    ~SoundChannel();
+    void init(SoundPool* soundPool);
+    void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume,
+            int priority, int loop, float rate);
+    void setVolume_l(float leftVolume, float rightVolume);
+    void setVolume(float leftVolume, float rightVolume);
+    void stop_l();
+    void stop();
+    void pause();
+    void autoPause();
+    void resume();
+    void autoResume();
+    void setRate(float rate);
+    int state() { return mState; }
+    void setPriority(int priority) { mPriority = priority; }
+    void setLoop(int loop);
+    int numChannels() { return mNumChannels; }
+    void clearNextEvent() { mNextEvent.clear(); }
+    void nextEvent();
+    int nextChannelID() { return mNextEvent.channelID(); }
+    void dump();
+
+private:
+    static void callback(int event, void* user, void *info);
+    void process(int event, void *info, unsigned long toggle);
+    bool doStop_l();
+
+    SoundPool*          mSoundPool;
+    AudioTrack*         mAudioTrack;
+    SoundEvent          mNextEvent;
+    Mutex               mLock;
+    int                 mState;
+    int                 mNumChannels;
+    int                 mPos;
+    int                 mAudioBufferSize;
+    unsigned long       mToggle;
+    bool                mAutoPaused;
+};
+
+// application object for managing a pool of sounds
+class SoundPool {
+    friend class SoundPoolThread;
+    friend class SoundChannel;
+public:
+    SoundPool(int maxChannels, audio_stream_type_t streamType, int srcQuality);
+    ~SoundPool();
+    int load(const char* url, int priority);
+    int load(int fd, int64_t offset, int64_t length, int priority);
+    bool unload(int sampleID);
+    int play(int sampleID, float leftVolume, float rightVolume, int priority,
+            int loop, float rate);
+    void pause(int channelID);
+    void autoPause();
+    void resume(int channelID);
+    void autoResume();
+    void stop(int channelID);
+    void setVolume(int channelID, float leftVolume, float rightVolume);
+    void setPriority(int channelID, int priority);
+    void setLoop(int channelID, int loop);
+    void setRate(int channelID, float rate);
+    audio_stream_type_t streamType() const { return mStreamType; }
+    int srcQuality() const { return mSrcQuality; }
+
+    // called from SoundPoolThread
+    void sampleLoaded(int sampleID);
+
+    // called from AudioTrack thread
+    void done_l(SoundChannel* channel);
+
+    // callback function
+    void setCallback(SoundPoolCallback* callback, void* user);
+    void* getUserData() { return mUserData; }
+
+private:
+    SoundPool() {} // no default constructor
+    bool startThreads();
+    void doLoad(sp<Sample>& sample);
+    sp<Sample> findSample(int sampleID) { return mSamples.valueFor(sampleID); }
+    SoundChannel* findChannel (int channelID);
+    SoundChannel* findNextChannel (int channelID);
+    SoundChannel* allocateChannel_l(int priority);
+    void moveToFront_l(SoundChannel* channel);
+    void notify(SoundPoolEvent event);
+    void dump();
+
+    // restart thread
+    void addToRestartList(SoundChannel* channel);
+    void addToStopList(SoundChannel* channel);
+    static int beginThread(void* arg);
+    int run();
+    void quit();
+
+    Mutex                   mLock;
+    Mutex                   mRestartLock;
+    Condition               mCondition;
+    SoundPoolThread*        mDecodeThread;
+    SoundChannel*           mChannelPool;
+    List<SoundChannel*>     mChannels;
+    List<SoundChannel*>     mRestart;
+    List<SoundChannel*>     mStop;
+    DefaultKeyedVector< int, sp<Sample> >   mSamples;
+    int                     mMaxChannels;
+    audio_stream_type_t     mStreamType;
+    int                     mSrcQuality;
+    int                     mAllocated;
+    int                     mNextSampleID;
+    int                     mNextChannelID;
+    bool                    mQuit;
+
+    // callback
+    Mutex                   mCallbackLock;
+    SoundPoolCallback*      mCallback;
+    void*                   mUserData;
+};
+
+} // end namespace android
+
+#endif /*SOUNDPOOL_H_*/
diff --git a/media/libmedia/SoundPoolThread.cpp b/media/libmedia/SoundPoolThread.cpp
new file mode 100644
index 0000000..ba3b482
--- /dev/null
+++ b/media/libmedia/SoundPoolThread.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoundPoolThread"
+#include "utils/Log.h"
+
+#include "SoundPoolThread.h"
+
+namespace android {
+
+void SoundPoolThread::write(SoundPoolMsg msg) {
+    Mutex::Autolock lock(&mLock);
+    while (mMsgQueue.size() >= maxMessages) {
+        mCondition.wait(mLock);
+    }
+
+    // if thread is quitting, don't add to queue
+    if (mRunning) {
+        mMsgQueue.push(msg);
+        mCondition.signal();
+    }
+}
+
+const SoundPoolMsg SoundPoolThread::read() {
+    Mutex::Autolock lock(&mLock);
+    while (mMsgQueue.size() == 0) {
+        mCondition.wait(mLock);
+    }
+    SoundPoolMsg msg = mMsgQueue[0];
+    mMsgQueue.removeAt(0);
+    mCondition.signal();
+    return msg;
+}
+
+void SoundPoolThread::quit() {
+    Mutex::Autolock lock(&mLock);
+    if (mRunning) {
+        mRunning = false;
+        mMsgQueue.clear();
+        mMsgQueue.push(SoundPoolMsg(SoundPoolMsg::KILL, 0));
+        mCondition.signal();
+        mCondition.wait(mLock);
+    }
+    ALOGV("return from quit");
+}
+
+SoundPoolThread::SoundPoolThread(SoundPool* soundPool) :
+    mSoundPool(soundPool)
+{
+    mMsgQueue.setCapacity(maxMessages);
+    if (createThreadEtc(beginThread, this, "SoundPoolThread")) {
+        mRunning = true;
+    }
+}
+
+SoundPoolThread::~SoundPoolThread()
+{
+    quit();
+}
+
+int SoundPoolThread::beginThread(void* arg) {
+    ALOGV("beginThread");
+    SoundPoolThread* soundPoolThread = (SoundPoolThread*)arg;
+    return soundPoolThread->run();
+}
+
+int SoundPoolThread::run() {
+    ALOGV("run");
+    for (;;) {
+        SoundPoolMsg msg = read();
+        ALOGV("Got message m=%d, mData=%d", msg.mMessageType, msg.mData);
+        switch (msg.mMessageType) {
+        case SoundPoolMsg::KILL:
+            ALOGV("goodbye");
+            return NO_ERROR;
+        case SoundPoolMsg::LOAD_SAMPLE:
+            doLoadSample(msg.mData);
+            break;
+        default:
+            ALOGW("run: Unrecognized message %d\n",
+                    msg.mMessageType);
+            break;
+        }
+    }
+}
+
+void SoundPoolThread::loadSample(int sampleID) {
+    write(SoundPoolMsg(SoundPoolMsg::LOAD_SAMPLE, sampleID));
+}
+
+void SoundPoolThread::doLoadSample(int sampleID) {
+    sp <Sample> sample = mSoundPool->findSample(sampleID);
+    status_t status = -1;
+    if (sample != 0) {
+        status = sample->doLoad();
+    }
+    mSoundPool->notify(SoundPoolEvent(SoundPoolEvent::SAMPLE_LOADED, sampleID, status));
+}
+
+} // end namespace android
diff --git a/media/libmedia/SoundPoolThread.h b/media/libmedia/SoundPoolThread.h
new file mode 100644
index 0000000..d388388
--- /dev/null
+++ b/media/libmedia/SoundPoolThread.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOUNDPOOLTHREAD_H_
+#define SOUNDPOOLTHREAD_H_
+
+#include <utils/threads.h>
+#include <utils/Vector.h>
+#include <media/AudioTrack.h>
+
+#include "SoundPool.h"
+
+namespace android {
+
+class SoundPoolMsg {
+public:
+    enum MessageType { INVALID, KILL, LOAD_SAMPLE };
+    SoundPoolMsg() : mMessageType(INVALID), mData(0) {}
+    SoundPoolMsg(MessageType MessageType, int data) :
+        mMessageType(MessageType), mData(data) {}
+    uint16_t         mMessageType;
+    uint16_t         mData;
+};
+
+/*
+ * This class handles background requests from the SoundPool
+ */
+class SoundPoolThread {
+public:
+    SoundPoolThread(SoundPool* SoundPool);
+    ~SoundPoolThread();
+    void loadSample(int sampleID);
+    void quit();
+    void write(SoundPoolMsg msg);
+
+private:
+    static const size_t maxMessages = 5;
+
+    static int beginThread(void* arg);
+    int run();
+    void doLoadSample(int sampleID);
+    const SoundPoolMsg read();
+
+    Mutex                   mLock;
+    Condition               mCondition;
+    Vector<SoundPoolMsg>    mMsgQueue;
+    SoundPool*              mSoundPool;
+    bool                    mRunning;
+};
+
+} // end namespace android
+
+#endif /*SOUNDPOOLTHREAD_H_*/
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index ba5c776..675c563 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -7,6 +7,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=               \
+    Crypto.cpp                  \
     MediaRecorderClient.cpp     \
     MediaPlayerService.cpp      \
     MetadataRetrieverClient.cpp \
@@ -38,12 +39,11 @@
         libstagefright_rtsp                     \
 
 LOCAL_C_INCLUDES :=                                               \
-	$(JNI_H_INCLUDE)                                                \
 	$(call include-path-for, graphics corecg)                       \
 	$(TOP)/frameworks/base/media/libstagefright/include             \
 	$(TOP)/frameworks/base/media/libstagefright/rtsp                \
 	$(TOP)/frameworks/native/include/media/openmax                  \
-	$(TOP)/external/tremolo/Tremolo
+	$(TOP)/external/tremolo/Tremolo                                 \
 
 LOCAL_MODULE:= libmediaplayerservice
 
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
new file mode 100644
index 0000000..e02035f
--- /dev/null
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Crypto"
+#include <utils/Log.h>
+
+#include "Crypto.h"
+
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+Crypto::Crypto() {
+}
+
+Crypto::~Crypto() {
+}
+
+status_t Crypto::initialize() {
+    return ERROR_UNSUPPORTED;
+}
+
+status_t Crypto::terminate() {
+    return ERROR_UNSUPPORTED;
+}
+
+status_t Crypto::setEntitlementKey(
+        const void *key, size_t keyLength) {
+    return ERROR_UNSUPPORTED;
+}
+
+status_t Crypto::setEntitlementControlMessage(
+        const void *msg, size_t msgLength) {
+    return ERROR_UNSUPPORTED;
+}
+
+ssize_t Crypto::decryptVideo(
+        const void *iv, size_t ivLength,
+        const void *srcData, size_t srcDataSize,
+        void *dstData, size_t dstDataOffset) {
+    return ERROR_UNSUPPORTED;
+}
+
+ssize_t Crypto::decryptAudio(
+        const void *iv, size_t ivLength,
+        const void *srcData, size_t srcDataSize,
+        void *dstData, size_t dstDataSize) {
+    return ERROR_UNSUPPORTED;
+}
+
+}  // namespace android
diff --git a/media/libmediaplayerservice/Crypto.h b/media/libmediaplayerservice/Crypto.h
new file mode 100644
index 0000000..9855496
--- /dev/null
+++ b/media/libmediaplayerservice/Crypto.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CRYPTO_H_
+
+#define CRYPTO_H_
+
+#include <media/ICrypto.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct Crypto : public BnCrypto {
+    Crypto();
+
+    virtual status_t initialize();
+    virtual status_t terminate();
+
+    virtual status_t setEntitlementKey(
+            const void *key, size_t keyLength);
+
+    virtual status_t setEntitlementControlMessage(
+            const void *msg, size_t msgLength);
+
+    virtual ssize_t decryptVideo(
+            const void *iv, size_t ivLength,
+            const void *srcData, size_t srcDataSize,
+            void *dstData, size_t dstDataOffset);
+
+    virtual ssize_t decryptAudio(
+            const void *iv, size_t ivLength,
+            const void *srcData, size_t srcDataSize,
+            void *dstData, size_t dstDataSize);
+
+protected:
+    virtual ~Crypto();
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(Crypto);
+};
+
+}  // namespace android
+
+#endif  // CRYPTO_H_
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 840e475..123d07f 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -70,6 +70,8 @@
 
 #include <OMX.h>
 
+#include "Crypto.h"
+
 namespace android {
 sp<MediaPlayerBase> createAAH_TXPlayer();
 sp<MediaPlayerBase> createAAH_RXPlayer();
@@ -292,6 +294,16 @@
     return mOMX;
 }
 
+sp<ICrypto> MediaPlayerService::makeCrypto() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mCrypto == NULL) {
+        mCrypto = new Crypto;
+    }
+
+    return mCrypto;
+}
+
 status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
 {
     const size_t SIZE = 256;
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index d4e0eb1..b08dd6c 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -240,6 +240,7 @@
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat);
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat);
     virtual sp<IOMX>            getOMX();
+    virtual sp<ICrypto>         makeCrypto();
 
     virtual status_t            dump(int fd, const Vector<String16>& args);
 
@@ -419,6 +420,7 @@
                 SortedVector< wp<MediaRecorderClient> > mMediaRecorderClients;
                 int32_t                     mNextConnId;
                 sp<IOMX>                    mOMX;
+                sp<ICrypto>                 mCrypto;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 1600141..5733229 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -125,6 +125,11 @@
 
         msg->setInt32("channel-count", numChannels);
         msg->setInt32("sample-rate", sampleRate);
+
+        int32_t isADTS;
+        if (meta->findInt32(kKeyIsADTS, &isADTS) && isADTS != 0) {
+            msg->setInt32("is-adts", true);
+        }
     }
 
     int32_t maxInputSize;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index e5ad4b7..db2beda 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -427,24 +427,34 @@
                 sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
                 CHECK(mem.get() != NULL);
 
-                IOMX::buffer_id buffer;
+                BufferInfo info;
+                info.mStatus = BufferInfo::OWNED_BY_US;
 
                 uint32_t requiresAllocateBufferBit =
                     (portIndex == kPortIndexInput)
                         ? OMXCodec::kRequiresAllocateBufferOnInputPorts
                         : OMXCodec::kRequiresAllocateBufferOnOutputPorts;
 
-                if (mQuirks & requiresAllocateBufferBit) {
+                if (portIndex == kPortIndexInput && (mFlags & kFlagIsSecure)) {
+                    mem.clear();
+
+                    void *ptr;
+                    err = mOMX->allocateBuffer(
+                            mNode, portIndex, def.nBufferSize, &info.mBufferID,
+                            &ptr);
+
+                    info.mData = new ABuffer(ptr, def.nBufferSize);
+                } else if (mQuirks & requiresAllocateBufferBit) {
                     err = mOMX->allocateBufferWithBackup(
-                            mNode, portIndex, mem, &buffer);
+                            mNode, portIndex, mem, &info.mBufferID);
                 } else {
-                    err = mOMX->useBuffer(mNode, portIndex, mem, &buffer);
+                    err = mOMX->useBuffer(mNode, portIndex, mem, &info.mBufferID);
                 }
 
-                BufferInfo info;
-                info.mBufferID = buffer;
-                info.mStatus = BufferInfo::OWNED_BY_US;
-                info.mData = new ABuffer(mem->pointer(), def.nBufferSize);
+                if (mem != NULL) {
+                    info.mData = new ABuffer(mem->pointer(), def.nBufferSize);
+                }
+
                 mBuffers[portIndex].push(info);
             }
         }
@@ -840,7 +850,13 @@
                 || !msg->findInt32("sample-rate", &sampleRate)) {
             err = INVALID_OPERATION;
         } else {
-            err = setupAACCodec(encoder, numChannels, sampleRate, bitRate);
+            int32_t isADTS;
+            if (!msg->findInt32("is-adts", &isADTS)) {
+                isADTS = 0;
+            }
+
+            err = setupAACCodec(
+                    encoder, numChannels, sampleRate, bitRate, isADTS != 0);
         }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
         err = setupAMRCodec(encoder, false /* isWAMR */, bitRate);
@@ -934,7 +950,11 @@
 
 status_t ACodec::setupAACCodec(
         bool encoder,
-        int32_t numChannels, int32_t sampleRate, int32_t bitRate) {
+        int32_t numChannels, int32_t sampleRate, int32_t bitRate, bool isADTS) {
+    if (encoder && isADTS) {
+        return -EINVAL;
+    }
+
     status_t err = setupRawAudioFormat(
             encoder ? kPortIndexInput : kPortIndexOutput,
             sampleRate,
@@ -1021,7 +1041,11 @@
 
     profile.nChannels = numChannels;
     profile.nSampleRate = sampleRate;
-    profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
+
+    profile.eAACStreamFormat =
+        isADTS
+            ? OMX_AUDIO_AACStreamFormatMP4ADTS
+            : OMX_AUDIO_AACStreamFormatMP4FF;
 
     return mOMX->setParameter(
             mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
@@ -2653,6 +2677,12 @@
     observer->setNotificationMessage(notify);
 
     mCodec->mComponentName = componentName;
+    mCodec->mFlags = 0;
+
+    if (componentName.endsWith(".secure")) {
+        mCodec->mFlags |= kFlagIsSecure;
+    }
+
     mCodec->mQuirks = quirks;
     mCodec->mOMX = omx;
     mCodec->mNode = node;
@@ -2701,6 +2731,7 @@
         mCodec->mNode = NULL;
         mCodec->mOMX.clear();
         mCodec->mQuirks = 0;
+        mCodec->mFlags = 0;
         mCodec->mComponentName.clear();
 
         mCodec->changeState(mCodec->mUninitializedState);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 7d7bd7d..8948abb 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -57,7 +57,6 @@
         avc_utils.cpp                     \
 
 LOCAL_C_INCLUDES:= \
-	$(JNI_H_INCLUDE) \
         $(TOP)/frameworks/base/include/media/stagefright/timedtext \
         $(TOP)/frameworks/native/include/media/hardware \
         $(TOP)/frameworks/native/include/media/openmax \
@@ -69,7 +68,6 @@
 LOCAL_SHARED_LIBRARIES := \
         libbinder \
         libcamera_client \
-        libchromium_net \
         libcrypto \
         libcutils \
         libdl \
@@ -102,14 +100,18 @@
         libstagefright_httplive \
         libstagefright_id3 \
         libFLAC \
-        libstagefright_chromium_http \
+
+ifneq ($(TARGET_BUILD_PDK), true)
+LOCAL_STATIC_LIBRARIES += \
+	libstagefright_chromium_http
+LOCAL_SHARED_LIBRARIES += \
+        libchromium_net
+LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1
+endif
 
 LOCAL_SHARED_LIBRARIES += libstlport
 include external/stlport/libstlport.mk
 
-# TODO: Chromium is always available, so this flag can be removed.
-LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1
-
 LOCAL_SHARED_LIBRARIES += \
         libstagefright_enc_common \
         libstagefright_avc_common \
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index a9e7f36..42b5c7e 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -22,10 +22,14 @@
 
 #include "include/SoftwareRenderer.h"
 
+#include <binder/IServiceManager.h>
 #include <gui/SurfaceTextureClient.h>
+#include <media/ICrypto.h>
+#include <media/IMediaPlayerService.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/ACodec.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
@@ -528,6 +532,12 @@
                         info.mOwnedByClient = false;
                         CHECK(msg->findBuffer(name.c_str(), &info.mData));
 
+                        if (portIndex == kPortIndexInput
+                                && (mFlags & kFlagIsSecure)) {
+                            info.mEncryptedData =
+                                new ABuffer(info.mData->capacity());
+                        }
+
                         buffers->push_back(info);
                     }
 
@@ -742,6 +752,59 @@
                 format->setInt32("encoder", true);
             }
 
+            if (flags & CONFIGURE_FLAG_SECURE) {
+                mFlags |= kFlagIsSecure;
+
+                sp<IServiceManager> sm = defaultServiceManager();
+
+                sp<IBinder> binder =
+                    sm->getService(String16("media.player"));
+
+                sp<IMediaPlayerService> service =
+                    interface_cast<IMediaPlayerService>(binder);
+
+                CHECK(service != NULL);
+
+                mCrypto = service->makeCrypto();
+
+                status_t err = mCrypto->initialize();
+
+                if (err == OK) {
+                    sp<ABuffer> emm;
+                    if (format->findBuffer("emm", &emm)) {
+                        err = mCrypto->setEntitlementKey(
+                                emm->data(), emm->size());
+                    }
+                }
+
+                if (err == OK) {
+                    sp<ABuffer> ecm;
+                    if (format->findBuffer("ecm", &ecm)) {
+                        CHECK_EQ(ecm->size(), 80u);
+
+                        // bytes 16..47 of the original ecm stream data.
+                        err = mCrypto->setEntitlementControlMessage(
+                                ecm->data() + 16, 32);
+                    }
+                }
+
+                if (err != OK) {
+                    ALOGE("failed to instantiate crypto service.");
+
+                    mCrypto.clear();
+
+                    setState(INITIALIZED);
+
+                    sp<AMessage> response = new AMessage;
+                    response->setInt32("err", UNKNOWN_ERROR);
+
+                    response->postReply(mReplyID);
+                    break;
+                }
+            } else {
+                mFlags &= ~kFlagIsSecure;
+            }
+
             mCodec->initiateConfigureComponent(format);
             break;
         }
@@ -983,7 +1046,10 @@
             for (size_t i = 0; i < srcBuffers.size(); ++i) {
                 const BufferInfo &info = srcBuffers.itemAt(i);
 
-                dstBuffers->push_back(info.mData);
+                dstBuffers->push_back(
+                        (portIndex == kPortIndexInput
+                            && (mFlags & kFlagIsSecure))
+                                ? info.mEncryptedData : info.mData);
             }
 
             (new AMessage)->postReply(replyID);
@@ -1037,10 +1103,15 @@
 }
 
 void MediaCodec::setState(State newState) {
-    if (newState == UNINITIALIZED) {
+    if (newState == INITIALIZED) {
         delete mSoftRenderer;
         mSoftRenderer = NULL;
 
+        if (mCrypto != NULL) {
+            mCrypto->terminate();
+            mCrypto.clear();
+        }
+
         mNativeWindow.clear();
 
         mOutputFormat.clear();
@@ -1150,6 +1221,43 @@
         info->mData->meta()->setInt32("csd", true);
     }
 
+    if (mFlags & kFlagIsSecure) {
+        uint8_t iv[16];
+        memset(iv, 0, sizeof(iv));
+
+        ssize_t outLength;
+
+        if (mFlags & kFlagIsSoftwareCodec) {
+            outLength = mCrypto->decryptAudio(
+                    (flags & BUFFER_FLAG_ENCRYPTED) ? iv : NULL,
+                    (flags & BUFFER_FLAG_ENCRYPTED) ? sizeof(iv) : 0,
+                        info->mEncryptedData->base() + offset,
+                        size,
+                        info->mData->base(),
+                        info->mData->capacity());
+        } else {
+            outLength = mCrypto->decryptVideo(
+                    (flags & BUFFER_FLAG_ENCRYPTED) ? iv : NULL,
+                    (flags & BUFFER_FLAG_ENCRYPTED) ? sizeof(iv) : 0,
+                        info->mEncryptedData->base() + offset,
+                        size,
+                        info->mData->base(),
+                        0  /* offset */);
+        }
+
+        if (outLength < 0) {
+            return outLength;
+        }
+
+        if ((size_t)outLength > info->mEncryptedData->capacity()) {
+            return -ERANGE;
+        }
+
+        info->mData->setRange(0, outLength);
+    } else if (flags & BUFFER_FLAG_ENCRYPTED) {
+        return -EINVAL;
+    }
+
     reply->setBuffer("buffer", info->mData);
     reply->post();
 
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index afd4763..224ec33 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -107,6 +107,11 @@
 
         msg->setInt32("channel-count", numChannels);
         msg->setInt32("sample-rate", sampleRate);
+
+        int32_t isADTS;
+        if (meta->findInt32(kKeyIsADTS, &isADTS)) {
+            msg->setInt32("is-adts", true);
+        }
     }
 
     int32_t maxInputSize;
@@ -232,6 +237,20 @@
         msg->setBuffer("csd-1", buffer);
     }
 
+    if (meta->findData(kKeyEMM, &type, &data, &size)) {
+        sp<ABuffer> emm = new ABuffer(size);
+        memcpy(emm->data(), data, size);
+
+        msg->setBuffer("emm", emm);
+    }
+
+    if (meta->findData(kKeyECM, &type, &data, &size)) {
+        sp<ABuffer> ecm = new ABuffer(size);
+        memcpy(ecm->data(), data, size);
+
+        msg->setBuffer("ecm", ecm);
+    }
+
     *format = msg;
 
     return OK;
@@ -267,13 +286,14 @@
     info->mFinalResult = OK;
     info->mSample = NULL;
     info->mSampleTimeUs = -1ll;
-    info->mFlags = 0;
+    info->mSampleFlags = 0;
+    info->mTrackFlags = 0;
 
     const char *mime;
     CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
 
     if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
-        info->mFlags |= kIsVorbis;
+        info->mTrackFlags |= kIsVorbis;
     }
 
     return OK;
@@ -288,6 +308,7 @@
             info->mSample = NULL;
 
             info->mSampleTimeUs = -1ll;
+            info->mSampleFlags = 0;
         }
     }
 }
@@ -306,6 +327,7 @@
                 info->mSample->release();
                 info->mSample = NULL;
                 info->mSampleTimeUs = -1ll;
+                info->mSampleFlags = 0;
             }
         } else if (info->mFinalResult != OK) {
             continue;
@@ -323,11 +345,25 @@
 
                 info->mFinalResult = err;
                 info->mSampleTimeUs = -1ll;
+                info->mSampleFlags = 0;
                 continue;
             } else {
                 CHECK(info->mSample != NULL);
                 CHECK(info->mSample->meta_data()->findInt64(
                             kKeyTime, &info->mSampleTimeUs));
+
+                info->mSampleFlags = 0;
+
+                int32_t val;
+                if (info->mSample->meta_data()->findInt32(
+                            kKeyIsSyncFrame, &val) && val != 0) {
+                    info->mSampleFlags |= SAMPLE_FLAG_SYNC;
+                }
+
+                if (info->mSample->meta_data()->findInt32(
+                            kKeyScrambling, &val) && val != 0) {
+                    info->mSampleFlags |= SAMPLE_FLAG_ENCRYPTED;
+                }
             }
         }
 
@@ -371,7 +407,7 @@
 
     size_t sampleSize = info->mSample->range_length();
 
-    if (info->mFlags & kIsVorbis) {
+    if (info->mTrackFlags & kIsVorbis) {
         // Each sample's data is suffixed by the number of page samples
         // or -1 if not available.
         sampleSize += sizeof(int32_t);
@@ -387,7 +423,7 @@
 
     memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length());
 
-    if (info->mFlags & kIsVorbis) {
+    if (info->mTrackFlags & kIsVorbis) {
         int32_t numPageSamples;
         if (!info->mSample->meta_data()->findInt32(
                     kKeyValidSamples, &numPageSamples)) {
@@ -430,4 +466,17 @@
     return OK;
 }
 
+status_t NuMediaExtractor::getSampleFlags(uint32_t *sampleFlags) {
+    ssize_t minIndex = fetchTrackSamples();
+
+    if (minIndex < 0) {
+        return ERROR_END_OF_STREAM;
+    }
+
+    TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
+    *sampleFlags = info->mSampleFlags;
+
+    return OK;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 8b6e9d5..9769f21 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -515,7 +515,12 @@
         CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
         CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
 
-        status_t err = setAACFormat(numChannels, sampleRate, bitRate);
+        int32_t isADTS;
+        if (!meta->findInt32(kKeyIsADTS, &isADTS)) {
+            isADTS = false;
+        }
+
+        status_t err = setAACFormat(numChannels, sampleRate, bitRate, isADTS);
         if (err != OK) {
             CODEC_LOGE("setAACFormat() failed (err = %d)", err);
             return err;
@@ -3386,11 +3391,17 @@
     }
 }
 
-status_t OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate, int32_t bitRate) {
-    if (numChannels > 2)
+status_t OMXCodec::setAACFormat(
+        int32_t numChannels, int32_t sampleRate, int32_t bitRate, bool isADTS) {
+    if (numChannels > 2) {
         ALOGW("Number of channels: (%d) \n", numChannels);
+    }
 
     if (mIsEncoder) {
+        if (isADTS) {
+            return -EINVAL;
+        }
+
         //////////////// input port ////////////////////
         setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
 
@@ -3445,7 +3456,9 @@
                 &profile, sizeof(profile));
 
         if (err != OK) {
-            CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed (err = %d)", err);
+            CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed "
+                       "(err = %d)",
+                       err);
             return err;
         }
     } else {
@@ -3459,13 +3472,19 @@
 
         profile.nChannels = numChannels;
         profile.nSampleRate = sampleRate;
-        profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
+
+        profile.eAACStreamFormat =
+            isADTS
+                ? OMX_AUDIO_AACStreamFormatMP4ADTS
+                : OMX_AUDIO_AACStreamFormatMP4FF;
 
         err = mOMX->setParameter(
                 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
 
         if (err != OK) {
-            CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed (err = %d)", err);
+            CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed "
+                       "(err = %d)",
+                       err);
             return err;
         }
     }
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 6d345bb..9df15eb 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -31,10 +31,6 @@
 
 #include <media/stagefright/foundation/ADebug.h>
 
-#ifdef ANDROID_SIMULATOR
-#include <jni.h>
-#endif
-
 namespace android {
 
 TimedEventQueue::TimedEventQueue()
@@ -193,27 +189,10 @@
 // static
 void *TimedEventQueue::ThreadWrapper(void *me) {
 
-#ifdef ANDROID_SIMULATOR
-    // The simulator runs everything as one process, so any
-    // Binder calls happen on this thread instead of a thread
-    // in another process. We therefore need to make sure that
-    // this thread can do calls into interpreted code.
-    // On the device this is not an issue because the remote
-    // thread will already be set up correctly for this.
-    JavaVM *vm;
-    int numvms;
-    JNI_GetCreatedJavaVMs(&vm, 1, &numvms);
-    JNIEnv *env;
-    vm->AttachCurrentThread(&env, NULL);
-#endif
-
     androidSetThreadPriority(0, ANDROID_PRIORITY_FOREGROUND);
 
     static_cast<TimedEventQueue *>(me)->threadEntry();
 
-#ifdef ANDROID_SIMULATOR
-    vm->DetachCurrentThread();
-#endif
     return NULL;
 }
 
diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk
index e37b4a8..d595686 100644
--- a/media/libstagefright/chromium_http/Android.mk
+++ b/media/libstagefright/chromium_http/Android.mk
@@ -1,5 +1,6 @@
 LOCAL_PATH:= $(call my-dir)
 
+ifneq ($(TARGET_BUILD_PDK), true)
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=       \
@@ -8,7 +9,6 @@
         support.cpp
 
 LOCAL_C_INCLUDES:= \
-        $(JNI_H_INCLUDE) \
         frameworks/base/media/libstagefright \
         $(TOP)/frameworks/native/include/media/openmax \
         external/chromium \
@@ -22,3 +22,4 @@
 LOCAL_MODULE:= libstagefright_chromium_http
 
 include $(BUILD_STATIC_LIBRARY)
+endif
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.cpp b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
index ea6c360..90f96c6 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
@@ -23,6 +23,7 @@
 #include "pvmp4audiodecoder_api.h"
 
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
 
 namespace android {
 
@@ -42,6 +43,7 @@
         OMX_COMPONENTTYPE **component)
     : SimpleSoftOMXComponent(name, callbacks, appData, component),
       mConfig(new tPVMP4AudioDecoderExternal),
+      mIsADTS(false),
       mDecoderBuf(NULL),
       mInputBufferCount(0),
       mUpsamplingFactor(2),
@@ -140,7 +142,12 @@
             aacParams->nAACtools = 0;
             aacParams->nAACERtools = 0;
             aacParams->eAACProfile = OMX_AUDIO_AACObjectMain;
-            aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
+
+            aacParams->eAACStreamFormat =
+                mIsADTS
+                    ? OMX_AUDIO_AACStreamFormatMP4ADTS
+                    : OMX_AUDIO_AACStreamFormatMP4FF;
+
             aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo;
 
             if (!isConfigured()) {
@@ -215,6 +222,15 @@
                 return OMX_ErrorUndefined;
             }
 
+            if (aacParams->eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4FF) {
+                mIsADTS = false;
+            } else if (aacParams->eAACStreamFormat
+                        == OMX_AUDIO_AACStreamFormatMP4ADTS) {
+                mIsADTS = true;
+            } else {
+                return OMX_ErrorUndefined;
+            }
+
             return OMX_ErrorNone;
         }
 
@@ -299,8 +315,35 @@
             mNumSamplesOutput = 0;
         }
 
-        mConfig->pInputBuffer = inHeader->pBuffer + inHeader->nOffset;
-        mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
+        if (mIsADTS) {
+            // skip 30 bits, aac_frame_length follows.
+            // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
+
+            const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
+
+            CHECK_GE(inHeader->nFilledLen, 7);
+
+            bool protectionAbsent = (adtsHeader[1] & 1);
+
+            unsigned aac_frame_length =
+                ((adtsHeader[3] & 3) << 11)
+                | (adtsHeader[4] << 3)
+                | (adtsHeader[5] >> 5);
+
+            CHECK_GE(inHeader->nFilledLen, aac_frame_length);
+
+            size_t headerSize = (protectionAbsent ? 7 : 9);
+
+            mConfig->pInputBuffer = (UChar *)adtsHeader + headerSize;
+            mConfig->inputBufferCurrentLength = aac_frame_length - headerSize;
+
+            inHeader->nOffset += headerSize;
+            inHeader->nFilledLen -= headerSize;
+        } else {
+            mConfig->pInputBuffer = inHeader->pBuffer + inHeader->nOffset;
+            mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
+        }
+
         mConfig->inputBufferMaxLength = 0;
         mConfig->inputBufferUsedLength = 0;
         mConfig->remainderBits = 0;
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.h b/media/libstagefright/codecs/aacdec/SoftAAC.h
index 963fd27..da0b8ed 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC.h
@@ -49,6 +49,7 @@
     };
 
     tPVMP4AudioDecoderExternal *mConfig;
+    bool mIsADTS;
     void *mDecoderBuf;
 
     size_t mInputBufferCount;
diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp
index 61b76cf..dee786d 100644
--- a/media/libstagefright/foundation/AString.cpp
+++ b/media/libstagefright/foundation/AString.cpp
@@ -310,6 +310,16 @@
     return !strncmp(mData, prefix, strlen(prefix));
 }
 
+bool AString::endsWith(const char *suffix) const {
+    size_t suffixLen = strlen(suffix);
+
+    if (mSize < suffixLen) {
+        return false;
+    }
+
+    return !strcmp(mData + mSize - suffixLen, suffix);
+}
+
 AString StringPrintf(const char *format, ...) {
     va_list ap;
     va_start(ap, format);
diff --git a/media/libstagefright/httplive/Android.mk b/media/libstagefright/httplive/Android.mk
index a5990c3..90cb448 100644
--- a/media/libstagefright/httplive/Android.mk
+++ b/media/libstagefright/httplive/Android.mk
@@ -8,7 +8,6 @@
         M3UParser.cpp           \
 
 LOCAL_C_INCLUDES:= \
-	$(JNI_H_INCLUDE) \
 	$(TOP)/frameworks/base/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax \
 	$(TOP)/external/openssl/include
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
index e67da4c..2cccb4f 100644
--- a/media/libstagefright/matroska/Android.mk
+++ b/media/libstagefright/matroska/Android.mk
@@ -5,7 +5,6 @@
         MatroskaExtractor.cpp
 
 LOCAL_C_INCLUDES:= \
-        $(JNI_H_INCLUDE) \
         $(TOP)/external/libvpx/mkvparser \
         $(TOP)/frameworks/native/include/media/openmax \
 
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index ac4c2a1..eaa139d 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -10,7 +10,6 @@
         MPEG2TSExtractor.cpp      \
 
 LOCAL_C_INCLUDES:= \
-	$(JNI_H_INCLUDE) \
 	$(TOP)/frameworks/base/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax
 
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index d708ba6..e1ac53c 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -117,6 +117,12 @@
 
             mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
 
+            int32_t scrambling;
+            if (buffer->meta()->findInt32("scrambling", &scrambling)
+                    && scrambling != 0) {
+                mediaBuffer->meta_data()->setInt32(kKeyScrambling, scrambling);
+            }
+
             *out = mediaBuffer;
             return OK;
         }
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 083c7ef..d20ecb6 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -1,8 +1,6 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
-
 LOCAL_SRC_FILES:=                     \
         OMX.cpp                       \
         OMXMaster.cpp                 \
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index 07d47a8..6aa7470 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -8,7 +8,6 @@
 	libstagefright libbinder libmedia libutils libstagefright_foundation
 
 LOCAL_C_INCLUDES := \
-	$(JNI_H_INCLUDE) \
 	frameworks/base/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax
 
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index b3bc37c..e0fe59b 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -18,7 +18,6 @@
         ASessionDescription.cpp     \
 
 LOCAL_C_INCLUDES:= \
-	$(JNI_H_INCLUDE) \
 	$(TOP)/frameworks/base/media/libstagefright/include \
 	$(TOP)/frameworks/native/include/media/openmax \
 	$(TOP)/external/openssl/include
@@ -45,7 +44,6 @@
         libstagefright_rtsp
 
 LOCAL_C_INCLUDES:= \
-	$(JNI_H_INCLUDE) \
 	frameworks/base/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax
 
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index d2d5f7b..58ef9e3 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -11,7 +11,6 @@
 
 LOCAL_CFLAGS += -Wno-multichar
 LOCAL_C_INCLUDES:= \
-        $(JNI_H_INCLUDE) \
         $(TOP)/frameworks/base/include/media/stagefright/timedtext \
         $(TOP)/frameworks/base/media/libstagefright
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e92e69c..c5ad0f5 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -442,11 +442,9 @@
         audio_format_t format,
         uint32_t channelMask,
         int frameCount,
-        // FIXME dead, remove from IAudioFlinger
-        uint32_t flags,
+        IAudioFlinger::track_flags_t flags,
         const sp<IMemory>& sharedBuffer,
         audio_io_handle_t output,
-        bool isTimed,
         int *sessionId,
         status_t *status)
 {
@@ -504,6 +502,7 @@
         }
         ALOGV("createTrack() lSessionId: %d", lSessionId);
 
+        bool isTimed = (flags & IAudioFlinger::TRACK_TIMED) != 0;
         track = thread->createTrack_l(client, streamType, sampleRate, format,
                 channelMask, frameCount, sharedBuffer, lSessionId, isTimed, &lStatus);
 
@@ -4676,8 +4675,7 @@
         audio_format_t format,
         uint32_t channelMask,
         int frameCount,
-        // FIXME dead, remove from IAudioFlinger
-        uint32_t flags,
+        IAudioFlinger::track_flags_t flags,
         int *sessionId,
         status_t *status)
 {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index d1950a3..795807d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -87,10 +87,9 @@
                                 audio_format_t format,
                                 uint32_t channelMask,
                                 int frameCount,
-                                uint32_t flags,
+                                IAudioFlinger::track_flags_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 audio_io_handle_t output,
-                                bool isTimed,
                                 int *sessionId,
                                 status_t *status);
 
@@ -101,7 +100,7 @@
                                 audio_format_t format,
                                 uint32_t channelMask,
                                 int frameCount,
-                                uint32_t flags,
+                                IAudioFlinger::track_flags_t flags,
                                 int *sessionId,
                                 status_t *status);