Merge "Add support for scaling mode parameter"
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index b81fe86..d43cb0b 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -116,13 +116,13 @@
     return cs->getCameraInfo(cameraId, cameraInfo);
 }
 
-sp<Camera> Camera::connect(int cameraId, bool force, bool keep)
+sp<Camera> Camera::connect(int cameraId)
 {
     ALOGV("connect");
     sp<Camera> c = new Camera();
     const sp<ICameraService>& cs = getCameraService();
     if (cs != 0) {
-        c->mCamera = cs->connect(c, cameraId, force, keep);
+        c->mCamera = cs->connect(c, cameraId);
     }
     if (c->mCamera != 0) {
         c->mCamera->asBinder()->linkToDeath(c);
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index c74298a..f2d367e 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -56,15 +56,12 @@
     }
 
     // connect to camera service
-    virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId,
-                                bool force, bool keep)
+    virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
         data.writeStrongBinder(cameraClient->asBinder());
         data.writeInt32(cameraId);
-        data.writeInt32(force);
-        data.writeInt32(keep);
         remote()->transact(BnCameraService::CONNECT, data, &reply);
         return interface_cast<ICamera>(reply.readStrongBinder());
     }
@@ -96,10 +93,7 @@
         case CONNECT: {
             CHECK_INTERFACE(ICameraService, data, reply);
             sp<ICameraClient> cameraClient = interface_cast<ICameraClient>(data.readStrongBinder());
-            const int cameraId = data.readInt32();
-            const int force = data.readInt32();
-            const int keep = data.readInt32();
-            sp<ICamera> camera = connect(cameraClient, cameraId, force, keep);
+            sp<ICamera> camera = connect(cameraClient, data.readInt32());
             reply->writeStrongBinder(camera->asBinder());
             return NO_ERROR;
         } break;
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index ece3c09..ebb5d58 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -39,8 +39,7 @@
     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"
-                    "\t\t[-D] decrypt input buffers\n",
+                    "\t\t[-S] allocate buffers from a surface\n",
                     me);
 
     exit(1);
@@ -61,33 +60,6 @@
     bool mIsAudio;
 };
 
-static sp<ICrypto> makeCrypto(
-        const uint8_t uuid[16], const void *data, size_t size) {
-    sp<IServiceManager> sm = defaultServiceManager();
-
-    sp<IBinder> binder =
-        sm->getService(String16("media.player"));
-
-    sp<IMediaPlayerService> service =
-        interface_cast<IMediaPlayerService>(binder);
-
-    CHECK(service != NULL);
-
-    sp<ICrypto> crypto = service->makeCrypto();
-
-    if (crypto == NULL || crypto->initCheck() != OK) {
-        return NULL;
-    }
-
-    status_t err = crypto->createPlugin(uuid, data, size);
-
-    if (err != OK) {
-        return NULL;
-    }
-
-    return crypto;
-}
-
 }  // namespace android
 
 static int decode(
@@ -95,8 +67,7 @@
         const char *path,
         bool useAudio,
         bool useVideo,
-        const android::sp<android::Surface> &surface,
-        bool decryptInputBuffers) {
+        const android::sp<android::Surface> &surface) {
     using namespace android;
 
     static int64_t kTimeout = 500ll;
@@ -107,8 +78,6 @@
         return 1;
     }
 
-    sp<ICrypto> crypto;
-
     KeyedVector<size_t, CodecState> stateByTrack;
 
     bool haveAudio = false;
@@ -144,62 +113,14 @@
         state->mNumBuffersDecoded = 0;
         state->mIsAudio = isAudio;
 
-        if (decryptInputBuffers && crypto == NULL) {
-            sp<ABuffer> emm;
-            CHECK(format->findBuffer("emm", &emm));
-
-            sp<ABuffer> ecm;
-            CHECK(format->findBuffer("ecm", &ecm));
-
-            struct WVOpaqueInitData {
-                uint8_t mEMM[16];
-                uint8_t mECM[32];
-
-            } opaque;
-
-            CHECK_EQ(emm->size(), sizeof(opaque.mEMM));
-            memcpy(opaque.mEMM, emm->data(), emm->size());
-
-            CHECK_EQ(ecm->size(), 80u);
-            // bytes 16..47 of the original ecm stream data.
-            memcpy(opaque.mECM, ecm->data() + 16, 32);
-
-            static const uint8_t kUUIDWidevine[16] = {
-                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-            };
-
-            crypto = makeCrypto(kUUIDWidevine, &opaque, sizeof(opaque));
-            CHECK(crypto != NULL);
-            CHECK_EQ(crypto->initCheck(), (status_t)OK);
-        }
-
-        if (decryptInputBuffers
-                && crypto->requiresSecureDecoderComponent(mime.c_str())) {
-            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 */);
-        }
+        state->mCodec = MediaCodec::CreateByType(
+                looper, mime.c_str(), false /* encoder */);
 
         CHECK(state->mCodec != NULL);
 
         err = state->mCodec->configure(
                 format, isVideo ? surface : NULL,
-                crypto,
+                NULL /* crypto */,
                 0 /* flags */);
 
         CHECK_EQ(err, (status_t)OK);
@@ -289,35 +210,12 @@
 
                     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);
-
-                        CryptoPlugin::SubSample ss;
-                        ss.mNumBytesOfClearData = 0;
-                        ss.mNumBytesOfEncryptedData = buffer->size();
-
-                        err = state->mCodec->queueSecureInputBuffer(
-                                index,
-                                0 /* offset */,
-                                &ss,
-                                1 /* numSubSamples */,
-                                NULL /* key */,
-                                NULL /* iv */,
-                                CryptoPlugin::kMode_AES_WV,
-                                timeUs,
-                                bufferFlags);
-                    } else {
-                        err = state->mCodec->queueInputBuffer(
-                                index,
-                                0 /* offset */,
-                                buffer->size(),
-                                timeUs,
-                                bufferFlags);
-                    }
+                    err = state->mCodec->queueInputBuffer(
+                            index,
+                            0 /* offset */,
+                            buffer->size(),
+                            timeUs,
+                            bufferFlags);
 
                     CHECK_EQ(err, (status_t)OK);
 
@@ -451,7 +349,6 @@
     bool useVideo = false;
     bool playback = false;
     bool useSurface = false;
-    bool decryptInputBuffers = false;
 
     int res;
     while ((res = getopt(argc, argv, "havpSD")) >= 0) {
@@ -480,12 +377,6 @@
                 break;
             }
 
-            case 'D':
-            {
-                decryptInputBuffers = true;
-                break;
-            }
-
             case '?':
             case 'h':
             default:
@@ -557,8 +448,7 @@
         player->stop();
         player->reset();
     } else {
-        decode(looper, argv[0],
-               useAudio, useVideo, surface, decryptInputBuffers);
+        decode(looper, argv[0], useAudio, useVideo, surface);
     }
 
     if (playback || (useSurface && useVideo)) {
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index 8ba0203..746f506 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -34,21 +34,7 @@
 static Vector<uid_t> trustedUids;
 
 static bool isProtectedCallAllowed() {
-    // TODO
-    // Following implementation is just for reference.
-    // Each OEM manufacturer should implement/replace with their own solutions.
-    bool result = false;
-
-    IPCThreadState* ipcState = IPCThreadState::self();
-    uid_t uid = ipcState->getCallingUid();
-
-    for (unsigned int i = 0; i < trustedUids.size(); ++i) {
-        if (trustedUids[i] == uid) {
-            result = true;
-            break;
-        }
-    }
-    return result;
+    return true;
 }
 
 void DrmManagerService::instantiate() {
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 3fedea0..234e165 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -72,7 +72,7 @@
     static  int32_t     getNumberOfCameras();
     static  status_t    getCameraInfo(int cameraId,
                                       struct CameraInfo* cameraInfo);
-    static  sp<Camera>  connect(int cameraId, bool force, bool keep);
+    static  sp<Camera>  connect(int cameraId);
             virtual     ~Camera();
             void        init();
 
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index 97e3169..7d70c1e 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -42,7 +42,7 @@
     virtual status_t        getCameraInfo(int cameraId,
                                           struct CameraInfo* cameraInfo) = 0;
     virtual sp<ICamera>     connect(const sp<ICameraClient>& cameraClient,
-                                    int cameraId, bool force, bool keep) = 0;
+                                    int cameraId) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 471f462..f73a317 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -185,7 +185,7 @@
                                         uint32_t samplingRate = 0,
                                         audio_format_t format = AUDIO_FORMAT_DEFAULT,
                                         uint32_t channels = AUDIO_CHANNEL_OUT_STEREO,
-                                        audio_policy_output_flags_t flags = AUDIO_POLICY_OUTPUT_FLAG_NONE);
+                                        audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE);
     static status_t startOutput(audio_io_handle_t output,
                                 audio_stream_type_t stream,
                                 int session = 0);
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 6de6486..4906bd3 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -139,7 +139,7 @@
      *                     latency of the track. The actual size selected by the AudioTrack could be
      *                     larger if the requested size is not compatible with current audio HAL
      *                     latency.
-     * flags:              See comments on audio_policy_output_flags_t in <system/audio_policy.h>.
+     * flags:              See comments on audio_output_flags_t in <system/audio.h>.
      * cbf:                Callback function. If not null, this function is called periodically
      *                     to request new PCM data.
      * user:               Context for use by the callback receiver.
@@ -155,7 +155,7 @@
                                     audio_format_t format = AUDIO_FORMAT_DEFAULT,
                                     int channelMask      = 0,
                                     int frameCount       = 0,
-                                    audio_policy_output_flags_t flags = AUDIO_POLICY_OUTPUT_FLAG_NONE,
+                                    audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                                     callback_t cbf       = NULL,
                                     void* user           = NULL,
                                     int notificationFrames = 0,
@@ -167,7 +167,7 @@
                                     int format = AUDIO_FORMAT_DEFAULT,
                                     int channelMask      = 0,
                                     int frameCount       = 0,
-                                    uint32_t flags       = (uint32_t) AUDIO_POLICY_OUTPUT_FLAG_NONE,
+                                    uint32_t flags       = (uint32_t) AUDIO_OUTPUT_FLAG_NONE,
                                     callback_t cbf       = 0,
                                     void* user           = 0,
                                     int notificationFrames = 0,
@@ -187,7 +187,7 @@
                                     audio_format_t format = AUDIO_FORMAT_DEFAULT,
                                     int channelMask     = 0,
                                     const sp<IMemory>& sharedBuffer = 0,
-                                    audio_policy_output_flags_t flags = AUDIO_POLICY_OUTPUT_FLAG_NONE,
+                                    audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                                     callback_t cbf      = NULL,
                                     void* user          = NULL,
                                     int notificationFrames = 0,
@@ -211,7 +211,7 @@
                             audio_format_t format = AUDIO_FORMAT_DEFAULT,
                             int channelMask     = 0,
                             int frameCount      = 0,
-                            audio_policy_output_flags_t flags = AUDIO_POLICY_OUTPUT_FLAG_NONE,
+                            audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                             callback_t cbf      = NULL,
                             void* user          = NULL,
                             int notificationFrames = 0,
@@ -476,7 +476,7 @@
                                  audio_format_t format,
                                  uint32_t channelMask,
                                  int frameCount,
-                                 audio_policy_output_flags_t flags,
+                                 audio_output_flags_t flags,
                                  const sp<IMemory>& sharedBuffer,
                                  audio_io_handle_t output);
             void flush_l();
@@ -517,7 +517,7 @@
     uint32_t                mNewPosition;
     uint32_t                mUpdatePeriod;
     bool                    mFlushed; // FIXME will be made obsolete by making flush() synchronous
-    audio_policy_output_flags_t mFlags;
+    audio_output_flags_t    mFlags;
     int                     mSessionId;
     int                     mAuxEffectId;
     mutable Mutex           mLock;
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 9e938d1..04ac3ee 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -133,7 +133,7 @@
                                          audio_format_t *pFormat,
                                          audio_channel_mask_t *pChannelMask,
                                          uint32_t *pLatencyMs,
-                                         audio_policy_output_flags_t flags) = 0;
+                                         audio_output_flags_t flags) = 0;
     virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
                                     audio_io_handle_t output2) = 0;
     virtual status_t closeOutput(audio_io_handle_t output) = 0;
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 04c927a..e160d70 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -52,7 +52,7 @@
                                         uint32_t samplingRate = 0,
                                         audio_format_t format = AUDIO_FORMAT_DEFAULT,
                                         uint32_t channels = 0,
-                                        audio_policy_output_flags_t flags = AUDIO_POLICY_OUTPUT_FLAG_NONE) = 0;
+                                        audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE) = 0;
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
                                  int session = 0) = 0;
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index d0db98e..8a87d83 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -129,10 +129,6 @@
 
     kKeyRequiresSecureBuffers = 'secu',  // bool (int32_t)
 
-    kKeyScrambling        = 'scrm',  // int32_t
-    kKeyEMM               = 'emm ',  // raw data
-    kKeyECM               = 'ecm ',  // raw data
-
     kKeyIsADTS            = 'adts',  // bool (int32_t)
 
     // If a MediaBuffer's data represents (at least partially) encrypted
@@ -156,6 +152,7 @@
     kKeyPlainSizes        = 'plai',  // size_t[]
     kKeyCryptoKey         = 'cryK',  // uint8_t[16]
     kKeyCryptoIV          = 'cryI',  // uint8_t[16]
+    kKeyCryptoMode        = 'cryM',  // int32_t
 };
 
 enum {
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index 07c7be5..9c61113 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -19,7 +19,9 @@
 
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/Errors.h>
+#include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
+#include <utils/String8.h>
 #include <utils/Vector.h>
 
 namespace android {
@@ -29,6 +31,7 @@
 struct MediaBuffer;
 struct MediaExtractor;
 struct MediaSource;
+struct MetaData;
 
 struct NuMediaExtractor : public RefBase {
     enum SampleFlags {
@@ -38,7 +41,11 @@
 
     NuMediaExtractor();
 
-    status_t setDataSource(const char *path);
+    status_t setDataSource(
+            const char *path,
+            const KeyedVector<String8, String8> *headers = NULL);
+
+    status_t setDataSource(int fd, off64_t offset, off64_t size);
 
     size_t countTracks() const;
     status_t getTrackFormat(size_t index, sp<AMessage> *format) const;
@@ -51,7 +58,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);
+    status_t getSampleMeta(sp<MetaData> *sampleMeta);
 
 protected:
     virtual ~NuMediaExtractor();
@@ -67,7 +74,6 @@
         status_t mFinalResult;
         MediaBuffer *mSample;
         int64_t mSampleTimeUs;
-        uint32_t mSampleFlags;
 
         uint32_t mTrackFlags;  // bitmask of "TrackFlags"
     };
diff --git a/include/media/stagefright/timedtext/TimedTextDriver.h b/include/media/stagefright/timedtext/TimedTextDriver.h
index e3ca536..1c5fd36 100644
--- a/include/media/stagefright/timedtext/TimedTextDriver.h
+++ b/include/media/stagefright/timedtext/TimedTextDriver.h
@@ -40,18 +40,24 @@
 
     status_t start();
     status_t pause();
-    status_t selectTrack(int32_t index);
-    status_t unselectTrack(int32_t index);
+    status_t selectTrack(size_t index);
+    status_t unselectTrack(size_t index);
 
     status_t seekToAsync(int64_t timeUs);
 
-    status_t addInBandTextSource(const sp<MediaSource>& source);
-    status_t addOutOfBandTextSource(const char *uri, const char *mimeType);
+    status_t addInBandTextSource(
+            size_t trackIndex, const sp<MediaSource>& source);
+
+    status_t addOutOfBandTextSource(
+            size_t trackIndex, const char *uri, const char *mimeType);
+
     // Caller owns the file desriptor and caller is responsible for closing it.
     status_t addOutOfBandTextSource(
-            int fd, off64_t offset, off64_t length, const char *mimeType);
+            size_t trackIndex, int fd, off64_t offset,
+            off64_t length, const char *mimeType);
 
-    void getTrackInfo(Parcel *parcel);
+    void getExternalTrackInfo(Parcel *parcel);
+    size_t countExternalTracks() const;
 
 private:
     Mutex mLock;
@@ -68,13 +74,17 @@
 
     // Variables to be guarded by mLock.
     State mState;
-    int32_t mCurrentTrackIndex;
-    Vector<sp<TimedTextSource> > mTextSourceVector;
+    size_t mCurrentTrackIndex;
+    KeyedVector<size_t, sp<TimedTextSource> > mTextSourceVector;
+    Vector<bool> mTextSourceTypeVector;
+
     // -- End of variables to be guarded by mLock
 
-    status_t selectTrack_l(int32_t index);
+    status_t selectTrack_l(size_t index);
+
     status_t createOutOfBandTextSource(
-            const char *mimeType, const sp<DataSource>& dataSource);
+            size_t trackIndex, const char* mimeType,
+            const sp<DataSource>& dataSource);
 
     DISALLOW_EVIL_CONSTRUCTORS(TimedTextDriver);
 };
diff --git a/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp b/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp
index d0ee51b..797686c 100755
--- a/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp
+++ b/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp
@@ -537,7 +537,7 @@
                 (numChannels == 2)
                     ? AUDIO_CHANNEL_OUT_STEREO
                     : AUDIO_CHANNEL_OUT_MONO,
-                0, AUDIO_POLICY_OUTPUT_FLAG_NONE, &AudioCallback, this, 0);
+                0, AUDIO_OUTPUT_FLAG_NONE, &AudioCallback, this, 0);
 
         if ((err = mAudioTrack->initCheck()) != OK) {
             delete mAudioTrack;
diff --git a/libvideoeditor/lvpp/VideoEditorPlayer.cpp b/libvideoeditor/lvpp/VideoEditorPlayer.cpp
index 1ba1f44..c9cff81 100755
--- a/libvideoeditor/lvpp/VideoEditorPlayer.cpp
+++ b/libvideoeditor/lvpp/VideoEditorPlayer.cpp
@@ -442,7 +442,7 @@
                 format,
                 channelMask,
                 frameCount,
-                AUDIO_POLICY_OUTPUT_FLAG_NONE,
+                AUDIO_OUTPUT_FLAG_NONE,
                 CallbackWrapper,
                 this);
     } else {
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 2596f07..4c41ba5 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -589,7 +589,7 @@
                                     uint32_t samplingRate,
                                     audio_format_t format,
                                     uint32_t channels,
-                                    audio_policy_output_flags_t flags)
+                                    audio_output_flags_t flags)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return 0;
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 6dc6c41..092b516 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -92,7 +92,7 @@
         audio_format_t format,
         int channelMask,
         int frameCount,
-        audio_policy_output_flags_t flags,
+        audio_output_flags_t flags,
         callback_t cbf,
         void* user,
         int notificationFrames,
@@ -124,7 +124,7 @@
       mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
 {
     mStatus = set((audio_stream_type_t)streamType, sampleRate, (audio_format_t)format, channelMask,
-            frameCount, (audio_policy_output_flags_t)flags, cbf, user, notificationFrames,
+            frameCount, (audio_output_flags_t)flags, cbf, user, notificationFrames,
             0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId);
 }
 
@@ -134,7 +134,7 @@
         audio_format_t format,
         int channelMask,
         const sp<IMemory>& sharedBuffer,
-        audio_policy_output_flags_t flags,
+        audio_output_flags_t flags,
         callback_t cbf,
         void* user,
         int notificationFrames,
@@ -174,7 +174,7 @@
         audio_format_t format,
         int channelMask,
         int frameCount,
-        audio_policy_output_flags_t flags,
+        audio_output_flags_t flags,
         callback_t cbf,
         void* user,
         int notificationFrames,
@@ -222,8 +222,8 @@
 
     // force direct flag if format is not linear PCM
     if (!audio_is_linear_pcm(format)) {
-        flags = (audio_policy_output_flags_t)
-                ((flags | AUDIO_POLICY_OUTPUT_FLAG_DIRECT) & ~AUDIO_POLICY_OUTPUT_FLAG_FAST);
+        flags = (audio_output_flags_t)
+                ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST);
     }
 
     if (!audio_is_output_channel(channelMask)) {
@@ -735,7 +735,7 @@
         audio_format_t format,
         uint32_t channelMask,
         int frameCount,
-        audio_policy_output_flags_t flags,
+        audio_output_flags_t flags,
         const sp<IMemory>& sharedBuffer,
         audio_io_handle_t output)
 {
@@ -761,14 +761,14 @@
 
     // Client decides whether the track is TIMED (see below), but can only express a preference
     // for FAST.  Server will perform additional tests.
-    if ((flags & AUDIO_POLICY_OUTPUT_FLAG_FAST) && !(
+    if ((flags & AUDIO_OUTPUT_FLAG_FAST) && !(
             // either of these use cases:
             // use case 1: shared buffer
             (sharedBuffer != 0) ||
             // use case 2: callback handler
             (mCbf != NULL))) {
-        ALOGW("AUDIO_POLICY_OUTPUT_FLAG_FAST denied");
-        flags = (audio_policy_output_flags_t) (flags & ~AUDIO_POLICY_OUTPUT_FLAG_FAST);
+        ALOGW("AUDIO_OUTPUT_FLAG_FAST denied");
+        flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST);
     }
     ALOGV("createTrack_l() output %d afFrameCount %d afLatency %d", output, afFrameCount, afLatency);
 
@@ -796,7 +796,7 @@
             if (mNotificationFramesAct > (uint32_t)frameCount/2) {
                 mNotificationFramesAct = frameCount/2;
             }
-            if (frameCount < minFrameCount && !(flags & AUDIO_POLICY_OUTPUT_FLAG_FAST)) {
+            if (frameCount < minFrameCount && !(flags & AUDIO_OUTPUT_FLAG_FAST)) {
                 // not ALOGW because it happens all the time when playing key clicks over A2DP
                 ALOGV("Minimum buffer size corrected from %d to %d",
                          frameCount, minFrameCount);
@@ -817,7 +817,7 @@
     if (mIsTimed) {
         trackFlags |= IAudioFlinger::TRACK_TIMED;
     }
-    if (flags & AUDIO_POLICY_OUTPUT_FLAG_FAST) {
+    if (flags & AUDIO_OUTPUT_FLAG_FAST) {
         trackFlags |= IAudioFlinger::TRACK_FAST;
     }
 
@@ -1033,7 +1033,7 @@
 
         size_t toWrite;
 
-        if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT)) {
+        if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
             // Divide capacity by 2 to take expansion into account
             toWrite = audioBuffer.size>>1;
             memcpy_to_i16_from_u8(audioBuffer.i16, (const uint8_t *) src, toWrite);
@@ -1190,7 +1190,7 @@
         // Divide buffer size by 2 to take into account the expansion
         // due to 8 to 16 bit conversion: the callback must fill only half
         // of the destination buffer
-        if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT)) {
+        if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
             audioBuffer.size >>= 1;
         }
 
@@ -1209,7 +1209,7 @@
         }
         if (writtenSize > reqSize) writtenSize = reqSize;
 
-        if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT)) {
+        if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
             // 8 to 16 bit conversion, note that source and destination are the same address
             memcpy_to_i16_from_u8(audioBuffer.i16, (const uint8_t *) audioBuffer.i8, writtenSize);
             writtenSize <<= 1;
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 81e259a..2b5126f 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -362,7 +362,7 @@
                                          audio_format_t *pFormat,
                                          audio_channel_mask_t *pChannelMask,
                                          uint32_t *pLatencyMs,
-                                         audio_policy_output_flags_t flags)
+                                         audio_output_flags_t flags)
     {
         Parcel data, reply;
         audio_devices_t devices = pDevices ? *pDevices : (audio_devices_t)0;
@@ -855,7 +855,7 @@
             audio_format_t format = (audio_format_t) data.readInt32();
             audio_channel_mask_t channelMask = (audio_channel_mask_t)data.readInt32();
             uint32_t latency = data.readInt32();
-            audio_policy_output_flags_t flags = (audio_policy_output_flags_t) data.readInt32();
+            audio_output_flags_t flags = (audio_output_flags_t) data.readInt32();
             audio_io_handle_t output = openOutput(module,
                                                  &devices,
                                                  &samplingRate,
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 5040bd9..7aab8d6 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -124,7 +124,7 @@
                                         uint32_t samplingRate,
                                         audio_format_t format,
                                         uint32_t channels,
-                                        audio_policy_output_flags_t flags)
+                                        audio_output_flags_t flags)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
@@ -418,8 +418,8 @@
             uint32_t samplingRate = data.readInt32();
             audio_format_t format = (audio_format_t) data.readInt32();
             uint32_t channels = data.readInt32();
-            audio_policy_output_flags_t flags =
-                    static_cast <audio_policy_output_flags_t>(data.readInt32());
+            audio_output_flags_t flags =
+                    static_cast <audio_output_flags_t>(data.readInt32());
 
             audio_io_handle_t output = getOutput(stream,
                                                  samplingRate,
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index cb5c7f3..58c6d38 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -93,7 +93,10 @@
         } break;
         case START: {
             CHECK_INTERFACE(IAudioRecord, data, reply);
-            reply->writeInt32(start(data.readInt32(), data.readInt32(), data.readInt32()));
+            pid_t tid = (pid_t) data.readInt32();
+            int event = data.readInt32();
+            int triggerSession = data.readInt32();
+            reply->writeInt32(start(tid, event, triggerSession));
             return NO_ERROR;
         } break;
         case STOP: {
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 52aee49..59e538f 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -94,7 +94,7 @@
             AUDIO_FORMAT_PCM_16_BIT,
             audio_channel_out_mask_from_count(pLibConfig->numChannels),
             mTrackBufferSize,
-            AUDIO_POLICY_OUTPUT_FLAG_NONE);
+            AUDIO_OUTPUT_FLAG_NONE);
 
     // create render and playback thread
     {
diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp
index 3b7b96a..4b318ed 100644
--- a/media/libmedia/SoundPool.cpp
+++ b/media/libmedia/SoundPool.cpp
@@ -608,10 +608,10 @@
         // 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);
+                channels, sample->getIMemory(), AUDIO_OUTPUT_FLAG_NONE, callback, userData);
 #else
         newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
-                channels, frameCount, AUDIO_POLICY_OUTPUT_FLAG_NONE, callback, userData,
+                channels, frameCount, AUDIO_OUTPUT_FLAG_NONE, callback, userData,
                 bufferFrames);
 #endif
         oldTrack = mAudioTrack;
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 717d316..253602d 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -1020,15 +1020,15 @@
     ALOGV("Create Track: %p", mpAudioTrack);
 
     mpAudioTrack->set(mStreamType,
-                      0,
+                      0,    // sampleRate
                       AUDIO_FORMAT_PCM_16_BIT,
                       AUDIO_CHANNEL_OUT_MONO,
-                      0,
-                      AUDIO_POLICY_OUTPUT_FLAG_NONE,
+                      0,    // frameCount
+                      AUDIO_OUTPUT_FLAG_FAST,
                       audioCallback,
-                      this,
-                      0,
-                      0,
+                      this, // user
+                      0,    // notificationFrames
+                      0,    // sharedBuffer
                       mThreadCanCallJava);
 
     if (mpAudioTrack->initCheck() != NO_ERROR) {
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
index 4491f2b..574ae71 100644
--- a/media/libmediaplayerservice/Crypto.cpp
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -32,6 +32,7 @@
 Crypto::Crypto()
     : mInitCheck(NO_INIT),
       mLibHandle(NULL),
+      mFactory(NULL),
       mPlugin(NULL) {
     mInitCheck = init();
 }
@@ -57,6 +58,8 @@
     mLibHandle = dlopen("libdrmdecrypt.so", RTLD_NOW);
 
     if (mLibHandle == NULL) {
+        ALOGE("Unable to locate libdrmdecrypt.so");
+
         return ERROR_UNSUPPORTED;
     }
 
@@ -66,6 +69,12 @@
 
     if (createCryptoFactory == NULL
             || ((mFactory = createCryptoFactory()) == NULL)) {
+        if (createCryptoFactory == NULL) {
+            ALOGE("Unable to find symbol 'createCryptoFactory'.");
+        } else {
+            ALOGE("createCryptoFactory() failed.");
+        }
+
         dlclose(mLibHandle);
         mLibHandle = NULL;
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 8bde8f1..7254599 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1587,7 +1587,7 @@
                 format,
                 channelMask,
                 frameCount,
-                AUDIO_POLICY_OUTPUT_FLAG_NONE,
+                AUDIO_OUTPUT_FLAG_NONE,
                 CallbackWrapper,
                 mCallbackData,
                 0,  // notification frames
@@ -1599,7 +1599,7 @@
                 format,
                 channelMask,
                 frameCount,
-                AUDIO_POLICY_OUTPUT_FLAG_NONE,
+                AUDIO_OUTPUT_FLAG_NONE,
                 NULL,
                 NULL,
                 0,
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 0f816e7..468fe2c 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -151,7 +151,7 @@
 
         mAudioTrack = new AudioTrack(
                 AUDIO_STREAM_MUSIC, mSampleRate, AUDIO_FORMAT_PCM_16_BIT, audioMask,
-                0, AUDIO_POLICY_OUTPUT_FLAG_NONE, &AudioCallback, this, 0);
+                0, AUDIO_OUTPUT_FLAG_NONE, &AudioCallback, this, 0);
 
         if ((err = mAudioTrack->initCheck()) != OK) {
             delete mAudioTrack;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 120a410..b67476b 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -356,6 +356,7 @@
 
     int64_t totalBitRate = 0;
 
+    mExtractor = extractor;
     for (size_t i = 0; i < extractor->countTracks(); ++i) {
         sp<MetaData> meta = extractor->getTrackMetaData(i);
 
@@ -443,7 +444,7 @@
                 }
             }
         } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
-            addTextSource(extractor->getTrack(i));
+            addTextSource(i, extractor->getTrack(i));
         }
     }
 
@@ -507,6 +508,7 @@
     mCachedSource.clear();
     mAudioTrack.clear();
     mVideoTrack.clear();
+    mExtractor.clear();
 
     // Shutdown audio first, so that the respone to the reset request
     // appears to happen instantaneously as far as the user is concerned
@@ -1331,7 +1333,7 @@
     mAudioTrack = source;
 }
 
-void AwesomePlayer::addTextSource(const sp<MediaSource>& source) {
+void AwesomePlayer::addTextSource(size_t trackIndex, const sp<MediaSource>& source) {
     Mutex::Autolock autoLock(mTimedTextLock);
     CHECK(source != NULL);
 
@@ -1339,7 +1341,7 @@
         mTextDriver = new TimedTextDriver(mListener);
     }
 
-    mTextDriver->addInBandTextSource(source);
+    mTextDriver->addInBandTextSource(trackIndex, source);
 }
 
 status_t AwesomePlayer::initAudioDecoder() {
@@ -2254,6 +2256,94 @@
     }
 }
 
+status_t AwesomePlayer::getTrackInfo(Parcel *reply) const {
+    Mutex::Autolock autoLock(mTimedTextLock);
+    if (mTextDriver == NULL) {
+        return INVALID_OPERATION;
+    }
+
+    reply->writeInt32(mTextDriver->countExternalTracks() +
+                mExtractor->countTracks());
+    for (size_t i = 0; i < mExtractor->countTracks(); ++i) {
+        sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+
+        const char *_mime;
+        CHECK(meta->findCString(kKeyMIMEType, &_mime));
+
+        String8 mime = String8(_mime);
+
+        reply->writeInt32(2); // 2 fields
+
+        if (!strncasecmp(mime.string(), "video/", 6)) {
+            reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO);
+        } else if (!strncasecmp(mime.string(), "audio/", 6)) {
+            reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO);
+        } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
+            reply->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
+        } else {
+            reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN);
+        }
+
+        const char *lang;
+        if (meta->findCString(kKeyMediaLanguage, &lang)) {
+            reply->writeString16(String16(lang));
+        } else {
+            reply->writeString16(String16(""));
+        }
+    }
+
+    mTextDriver->getExternalTrackInfo(reply);
+    return OK;
+}
+
+// FIXME:
+// At present, only timed text track is able to be selected or unselected.
+status_t AwesomePlayer::selectTrack(size_t trackIndex, bool select) {
+    Mutex::Autolock autoLock(mTimedTextLock);
+    if (mTextDriver == NULL) {
+        return INVALID_OPERATION;
+    }
+
+    if (trackIndex >= mExtractor->countTracks()
+                + mTextDriver->countExternalTracks()) {
+        return BAD_VALUE;
+    }
+
+    if (trackIndex < mExtractor->countTracks()) {
+        sp<MetaData> meta = mExtractor->getTrackMetaData(trackIndex);
+        const char *_mime;
+        CHECK(meta->findCString(kKeyMIMEType, &_mime));
+        String8 mime = String8(_mime);
+
+        if (strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) {
+            return ERROR_UNSUPPORTED;
+        }
+    }
+
+    status_t err = OK;
+    if (select) {
+        err = mTextDriver->selectTrack(trackIndex);
+        if (err == OK) {
+            modifyFlags(TEXTPLAYER_INITIALIZED, SET);
+            if (mFlags & PLAYING && !(mFlags & TEXT_RUNNING)) {
+                mTextDriver->start();
+                modifyFlags(TEXT_RUNNING, SET);
+            }
+        }
+    } else {
+        err = mTextDriver->unselectTrack(trackIndex);
+        if (err == OK) {
+            modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR);
+            modifyFlags(TEXT_RUNNING, CLEAR);
+        }
+    }
+    return err;
+}
+
+size_t AwesomePlayer::countTracks() const {
+    return mExtractor->countTracks() + mTextDriver->countExternalTracks();
+}
+
 status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) {
     if (NULL == reply) {
         return android::BAD_VALUE;
@@ -2266,12 +2356,7 @@
     switch(methodId) {
         case INVOKE_ID_GET_TRACK_INFO:
         {
-            Mutex::Autolock autoLock(mTimedTextLock);
-            if (mTextDriver == NULL) {
-                return INVALID_OPERATION;
-            }
-            mTextDriver->getTrackInfo(reply);
-            return OK;
+            return getTrackInfo(reply);
         }
         case INVOKE_ID_ADD_EXTERNAL_SOURCE:
         {
@@ -2282,7 +2367,8 @@
             // String values written in Parcel are UTF-16 values.
             String8 uri(request.readString16());
             String8 mimeType(request.readString16());
-            return mTextDriver->addOutOfBandTextSource(uri, mimeType);
+            size_t nTracks = countTracks();
+            return mTextDriver->addOutOfBandTextSource(nTracks, uri, mimeType);
         }
         case INVOKE_ID_ADD_EXTERNAL_SOURCE_FD:
         {
@@ -2294,40 +2380,19 @@
             off64_t offset = request.readInt64();
             off64_t length  = request.readInt64();
             String8 mimeType(request.readString16());
+            size_t nTracks = countTracks();
             return mTextDriver->addOutOfBandTextSource(
-                    fd, offset, length, mimeType);
+                    nTracks, fd, offset, length, mimeType);
         }
         case INVOKE_ID_SELECT_TRACK:
         {
-            Mutex::Autolock autoLock(mTimedTextLock);
-            if (mTextDriver == NULL) {
-                return INVALID_OPERATION;
-            }
-
-            status_t err = mTextDriver->selectTrack(
-                    request.readInt32());
-            if (err == OK) {
-                modifyFlags(TEXTPLAYER_INITIALIZED, SET);
-                if (mFlags & PLAYING && !(mFlags & TEXT_RUNNING)) {
-                    mTextDriver->start();
-                    modifyFlags(TEXT_RUNNING, SET);
-                }
-            }
-            return err;
+            int trackIndex = request.readInt32();
+            return selectTrack(trackIndex, true);
         }
         case INVOKE_ID_UNSELECT_TRACK:
         {
-            Mutex::Autolock autoLock(mTimedTextLock);
-            if (mTextDriver == NULL) {
-                return INVALID_OPERATION;
-            }
-            status_t err = mTextDriver->unselectTrack(
-                    request.readInt32());
-            if (err == OK) {
-                modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR);
-                modifyFlags(TEXT_RUNNING, CLEAR);
-            }
-            return err;
+            int trackIndex = request.readInt32();
+            return selectTrack(trackIndex, false);
         }
         default:
         {
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index fd3f892..3ddad93 100755
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -182,7 +182,7 @@
     int32_t cameraId) {
 
     if (camera == 0) {
-        mCamera = Camera::connect(cameraId, false, false);
+        mCamera = Camera::connect(cameraId);
         if (mCamera == 0) return -EBUSY;
         mCameraFlags &= ~FLAGS_HOT_CAMERA;
     } else {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index d0a7880..3400724 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -133,16 +133,46 @@
 // static
 sp<DataSource> DataSource::CreateFromURI(
         const char *uri, const KeyedVector<String8, String8> *headers) {
+    bool isWidevine = !strncasecmp("widevine://", uri, 11);
+
     sp<DataSource> source;
     if (!strncasecmp("file://", uri, 7)) {
         source = new FileSource(uri + 7);
     } else if (!strncasecmp("http://", uri, 7)
-            || !strncasecmp("https://", uri, 8)) {
+            || !strncasecmp("https://", uri, 8)
+            || isWidevine) {
         sp<HTTPBase> httpSource = HTTPBase::Create();
+
+        String8 tmp;
+        if (isWidevine) {
+            tmp = String8("http://");
+            tmp.append(uri + 11);
+
+            uri = tmp.string();
+        }
+
         if (httpSource->connect(uri, headers) != OK) {
             return NULL;
         }
-        source = new NuCachedSource2(httpSource);
+
+        if (!isWidevine) {
+            String8 cacheConfig;
+            bool disconnectAtHighwatermark;
+            if (headers != NULL) {
+                KeyedVector<String8, String8> copy = *headers;
+                NuCachedSource2::RemoveCacheSpecificHeaders(
+                        &copy, &cacheConfig, &disconnectAtHighwatermark);
+            }
+
+            source = new NuCachedSource2(
+                    httpSource,
+                    cacheConfig.isEmpty() ? NULL : cacheConfig.string());
+        } else {
+            // We do not want that prefetching, caching, datasource wrapper
+            // in the widevine:// case.
+            source = httpSource;
+        }
+
 # if CHROMIUM_AVAILABLE
     } else if (!strncasecmp("data:", uri, 5)) {
         source = new DataUriSource(uri);
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 224ec33..00bb74f 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -21,11 +21,13 @@
 #include <media/stagefright/NuMediaExtractor.h>
 
 #include "include/ESDS.h"
+#include "include/WVMExtractor.h"
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSource.h>
+#include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
@@ -51,14 +53,59 @@
     mSelectedTracks.clear();
 }
 
-status_t NuMediaExtractor::setDataSource(const char *path) {
-    sp<DataSource> dataSource = DataSource::CreateFromURI(path);
+status_t NuMediaExtractor::setDataSource(
+        const char *path, const KeyedVector<String8, String8> *headers) {
+    if (mImpl != NULL) {
+        return -EINVAL;
+    }
+
+    sp<DataSource> dataSource =
+        DataSource::CreateFromURI(path, headers);
 
     if (dataSource == NULL) {
         return -ENOENT;
     }
 
-    mImpl = MediaExtractor::Create(dataSource);
+    if (!strncasecmp("widevine://", path, 11)) {
+        String8 mimeType;
+        float confidence;
+        sp<AMessage> dummy;
+        bool success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
+
+        if (!success
+                || strcasecmp(
+                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
+            return ERROR_UNSUPPORTED;
+        }
+
+        sp<WVMExtractor> extractor = new WVMExtractor(dataSource);
+        extractor->setAdaptiveStreamingMode(true);
+
+        mImpl = extractor;
+    } else {
+        mImpl = MediaExtractor::Create(dataSource);
+    }
+
+    if (mImpl == NULL) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    return OK;
+}
+
+status_t NuMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
+    if (mImpl != NULL) {
+        return -EINVAL;
+    }
+
+    sp<FileSource> fileSource = new FileSource(dup(fd), offset, size);
+
+    status_t err = fileSource->initCheck();
+    if (err != OK) {
+        return err;
+    }
+
+    mImpl = MediaExtractor::Create(fileSource);
 
     if (mImpl == NULL) {
         return ERROR_UNSUPPORTED;
@@ -91,6 +138,11 @@
     sp<AMessage> msg = new AMessage;
     msg->setString("mime", mime);
 
+    int64_t durationUs;
+    if (meta->findInt64(kKeyDuration, &durationUs)) {
+        msg->setInt64("durationUs", durationUs);
+    }
+
     if (!strncasecmp("video/", mime, 6)) {
         int32_t width, height;
         CHECK(meta->findInt32(kKeyWidth, &width));
@@ -237,20 +289,6 @@
         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;
@@ -286,7 +324,6 @@
     info->mFinalResult = OK;
     info->mSample = NULL;
     info->mSampleTimeUs = -1ll;
-    info->mSampleFlags = 0;
     info->mTrackFlags = 0;
 
     const char *mime;
@@ -308,7 +345,6 @@
             info->mSample = NULL;
 
             info->mSampleTimeUs = -1ll;
-            info->mSampleFlags = 0;
         }
     }
 }
@@ -327,7 +363,6 @@
                 info->mSample->release();
                 info->mSample = NULL;
                 info->mSampleTimeUs = -1ll;
-                info->mSampleFlags = 0;
             }
         } else if (info->mFinalResult != OK) {
             continue;
@@ -345,25 +380,11 @@
 
                 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;
-                }
             }
         }
 
@@ -377,7 +398,13 @@
 }
 
 status_t NuMediaExtractor::seekTo(int64_t timeUs) {
-    return fetchTrackSamples(timeUs);
+    ssize_t minIndex = fetchTrackSamples(timeUs);
+
+    if (minIndex < 0) {
+        return ERROR_END_OF_STREAM;
+    }
+
+    return OK;
 }
 
 status_t NuMediaExtractor::advance() {
@@ -466,7 +493,9 @@
     return OK;
 }
 
-status_t NuMediaExtractor::getSampleFlags(uint32_t *sampleFlags) {
+status_t NuMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) {
+    *sampleMeta = NULL;
+
     ssize_t minIndex = fetchTrackSamples();
 
     if (minIndex < 0) {
@@ -474,7 +503,7 @@
     }
 
     TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
-    *sampleFlags = info->mSampleFlags;
+    *sampleMeta = info->mSample->meta_data();
 
     return OK;
 }
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index efc71a8..5d72a05 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -55,6 +55,8 @@
     mBufferQueue = new BufferQueue(true, MIN_UNDEQUEUED_BUFFERS);
     mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight);
     mBufferQueue->setSynchronousMode(true);
+    mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER |
+            GRALLOC_USAGE_HW_TEXTURE);
 
     sp<ISurfaceComposer> composer(ComposerService::getComposerService());
 
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index dac8106..effe336 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -59,10 +59,14 @@
                 "_ZN7android11GetInstanceENS_2spINS_10DataSourceEEE");
 
     if (getInstanceFunc) {
-        CHECK(source->DrmInitialization(MEDIA_MIMETYPE_CONTAINER_WVM) != NULL);
-        mImpl = (*getInstanceFunc)(source);
-        CHECK(mImpl != NULL);
-        setDrmFlag(true);
+        if (source->DrmInitialization(
+                MEDIA_MIMETYPE_CONTAINER_WVM) != NULL) {
+            mImpl = (*getInstanceFunc)(source);
+            CHECK(mImpl != NULL);
+            setDrmFlag(true);
+        } else {
+            ALOGE("Drm manager failed to initialize.");
+        }
     } else {
         ALOGE("Failed to locate GetInstance in libwvm.so");
     }
diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk
index 5b3d216..2808745 100644
--- a/media/libstagefright/codecs/aacdec/Android.mk
+++ b/media/libstagefright/codecs/aacdec/Android.mk
@@ -12,7 +12,8 @@
           frameworks/av/media/libstagefright/include \
           frameworks/native/include/media/openmax \
           external/aac/libAACdec/include \
-          external/aac/libCDK/include \
+          external/aac/libPCMutils/include \
+          external/aac/libFDK/include \
           external/aac/libMpegTPDec/include \
           external/aac/libSBRdec/include \
           external/aac/libSYS/include
@@ -20,7 +21,7 @@
   LOCAL_CFLAGS :=
 
   LOCAL_STATIC_LIBRARIES := \
-          libAACdec libMpegTPDec libSBRdec libCDK libSYS
+          libAACdec libMpegTPDec libSBRdec libPCMutils libFDK libSYS
 
   LOCAL_SHARED_LIBRARIES := \
           libstagefright_omx libstagefright_foundation libutils
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 4589d37..27cf5b9 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -26,23 +26,6 @@
 
 namespace android {
 
-static Mutex gAACLibraryLock;
-static int gAACLibraryCount = 0;
-
-void initializeAACLibrary() {
-  Mutex::Autolock autoLock(gAACLibraryLock);
-  if (gAACLibraryCount++ == 0) {
-    CDKprolog();
-  }
-}
-
-void cleanupAACLibrary() {
-  Mutex::Autolock autoLock(gAACLibraryLock);
-  if (--gAACLibraryCount == 0) {
-    CDKepilog();
-  }
-}
-
 template<class T>
 static void InitOMXParams(T *params) {
     params->nSize = sizeof(T);
@@ -63,17 +46,16 @@
       mIsADTS(false),
       mInputBufferCount(0),
       mSignalledError(false),
+      mInputDiscontinuity(false),
       mAnchorTimeUs(0),
       mNumSamplesOutput(0),
       mOutputPortSettingsChange(NONE) {
-    initializeAACLibrary();
     initPorts();
     CHECK_EQ(initDecoder(), (status_t)OK);
 }
 
 SoftAAC2::~SoftAAC2() {
     aacDecoder_Close(mAACDecoder);
-    cleanupAACLibrary();
 }
 
 void SoftAAC2::initPorts() {
@@ -102,7 +84,7 @@
     def.eDir = OMX_DirOutput;
     def.nBufferCountMin = kNumBuffers;
     def.nBufferCountActual = def.nBufferCountMin;
-    def.nBufferSize = 8192;
+    def.nBufferSize = 8192 * 2;
     def.bEnabled = OMX_TRUE;
     def.bPopulated = OMX_FALSE;
     def.eDomain = OMX_PortDomainAudio;
@@ -183,6 +165,10 @@
             pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
             pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
             pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+            pcmParams->eChannelMapping[2] = OMX_AUDIO_ChannelCF;
+            pcmParams->eChannelMapping[3] = OMX_AUDIO_ChannelLFE;
+            pcmParams->eChannelMapping[4] = OMX_AUDIO_ChannelLS;
+            pcmParams->eChannelMapping[5] = OMX_AUDIO_ChannelRS;
 
             if (!isConfigured()) {
                 pcmParams->nChannels = 1;
@@ -360,15 +346,17 @@
         INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>(outHeader->pBuffer + outHeader->nOffset);
         bytesValid[0] = inBufferLength[0];
 
+        int flags = mInputDiscontinuity ? AACDEC_INTR : 0;
         int prevSampleRate = mStreamInfo->sampleRate;
         decoderErr = aacDecoder_Fill(mAACDecoder,
-                                      inBuffer,
-                                      inBufferLength,
-                                      bytesValid);
+                                     inBuffer,
+                                     inBufferLength,
+                                     bytesValid);
         decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
                                             outBuffer,
                                             outHeader->nAllocLen,
-                                            /* flags */ 0);
+                                            flags);
+        mInputDiscontinuity = false;
 
         /*
          * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
@@ -447,13 +435,9 @@
 
 void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) {
     if (portIndex == 0) {
-
         // Make sure that the next buffer output does not still
         // depend on fragments from the last one decoded.
-        aacDecoder_DecodeFrame(mAACDecoder,
-                               NULL,
-                               0,
-                               AACDEC_FLUSH);
+        mInputDiscontinuity = true;
     }
 }
 
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h
index 828b34e..d93685c 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -52,6 +52,7 @@
     bool mIsADTS;
     size_t mInputBufferCount;
     bool mSignalledError;
+    bool mInputDiscontinuity;
     int64_t mAnchorTimeUs;
     int64_t mNumSamplesOutput;
 
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 06e9468..9115f91 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -235,6 +235,7 @@
     mutable Mutex mTimedTextLock;
 
     sp<WVMExtractor> mWVMExtractor;
+    sp<MediaExtractor> mExtractor;
 
     status_t setDataSource_l(
             const char *uri,
@@ -257,7 +258,7 @@
     void setVideoSource(sp<MediaSource> source);
     status_t initVideoDecoder(uint32_t flags = 0);
 
-    void addTextSource(const sp<MediaSource>& source);
+    void addTextSource(size_t trackIndex, const sp<MediaSource>& source);
 
     void onStreamDone();
 
@@ -318,6 +319,14 @@
         Vector<TrackStat> mTracks;
     } mStats;
 
+    status_t getTrackInfo(Parcel* reply) const;
+
+    // when select is true, the given track is selected.
+    // otherwise, the given track is unselected.
+    status_t selectTrack(size_t trackIndex, bool select);
+
+    size_t countTracks() const;
+
     AwesomePlayer(const AwesomePlayer &);
     AwesomePlayer &operator=(const AwesomePlayer &);
 };
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index e1ac53c..d708ba6 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -117,12 +117,6 @@
 
             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/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index 10713fe..466f521 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -486,6 +486,10 @@
     mSTC = new SurfaceTextureClient(iST);
     mANW = mSTC;
 
+    if (mEglSurface != EGL_NO_SURFACE) {
+        EXPECT_TRUE(eglDestroySurface(mEglDisplay, mEglSurface));
+        mEglSurface = EGL_NO_SURFACE;
+    }
     mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
                                 mANW.get(), NULL);
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
@@ -783,6 +787,11 @@
     DummyRecorder writer(mSMS);
     writer.start();
 
+    if (mEglSurface != EGL_NO_SURFACE) {
+        EXPECT_TRUE(eglDestroySurface(mEglDisplay, mEglSurface));
+        mEglSurface = EGL_NO_SURFACE;
+    }
+
     mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
                                 mANW.get(), NULL);
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp
index a99d882..e26f517 100644
--- a/media/libstagefright/timedtext/TimedTextDriver.cpp
+++ b/media/libstagefright/timedtext/TimedTextDriver.cpp
@@ -52,16 +52,13 @@
 
 TimedTextDriver::~TimedTextDriver() {
     mTextSourceVector.clear();
+    mTextSourceTypeVector.clear();
     mLooper->stop();
 }
 
-status_t TimedTextDriver::selectTrack_l(int32_t index) {
-    if (index >= (int)(mTextSourceVector.size())) {
-        return BAD_VALUE;
-    }
-
+status_t TimedTextDriver::selectTrack_l(size_t index) {
     sp<TimedTextSource> source;
-    source = mTextSourceVector.itemAt(index);
+    source = mTextSourceVector.valueFor(index);
     mPlayer->setDataSource(source);
     if (mState == UNINITIALIZED) {
         mState = PAUSED;
@@ -108,7 +105,7 @@
     return OK;
 }
 
-status_t TimedTextDriver::selectTrack(int32_t index) {
+status_t TimedTextDriver::selectTrack(size_t index) {
     status_t ret = OK;
     Mutex::Autolock autoLock(mLock);
     switch (mState) {
@@ -130,7 +127,7 @@
     return ret;
 }
 
-status_t TimedTextDriver::unselectTrack(int32_t index) {
+status_t TimedTextDriver::unselectTrack(size_t index) {
     if (mCurrentTrackIndex != index) {
         return INVALID_OPERATION;
     }
@@ -149,19 +146,21 @@
 }
 
 status_t TimedTextDriver::addInBandTextSource(
-        const sp<MediaSource>& mediaSource) {
+        size_t trackIndex, const sp<MediaSource>& mediaSource) {
     sp<TimedTextSource> source =
             TimedTextSource::CreateTimedTextSource(mediaSource);
     if (source == NULL) {
         return ERROR_UNSUPPORTED;
     }
     Mutex::Autolock autoLock(mLock);
-    mTextSourceVector.add(source);
+    mTextSourceVector.add(trackIndex, source);
+    mTextSourceTypeVector.add(true);
     return OK;
 }
 
 status_t TimedTextDriver::addOutOfBandTextSource(
-        const char *uri, const char *mimeType) {
+        size_t trackIndex, const char *uri, const char *mimeType) {
+
     // To support local subtitle file only for now
     if (strncasecmp("file://", uri, 7)) {
         ALOGE("uri('%s') is not a file", uri);
@@ -170,11 +169,11 @@
 
     sp<DataSource> dataSource =
             DataSource::CreateFromURI(uri);
-    return createOutOfBandTextSource(mimeType, dataSource);
+    return createOutOfBandTextSource(trackIndex, mimeType, dataSource);
 }
 
 status_t TimedTextDriver::addOutOfBandTextSource(
-        int fd, off64_t offset, off64_t length, const char *mimeType) {
+        size_t trackIndex, int fd, off64_t offset, off64_t length, const char *mimeType) {
 
     if (fd < 0) {
         ALOGE("Invalid file descriptor: %d", fd);
@@ -182,11 +181,13 @@
     }
 
     sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
-    return createOutOfBandTextSource(mimeType, dataSource);
+    return createOutOfBandTextSource(trackIndex, mimeType, dataSource);
 }
 
 status_t TimedTextDriver::createOutOfBandTextSource(
-        const char *mimeType, const sp<DataSource>& dataSource) {
+        size_t trackIndex,
+        const char *mimeType,
+        const sp<DataSource>& dataSource) {
 
     if (dataSource == NULL) {
         return ERROR_UNSUPPORTED;
@@ -199,28 +200,40 @@
     }
 
     if (source == NULL) {
+        ALOGE("Failed to create timed text source");
         return ERROR_UNSUPPORTED;
     }
 
     Mutex::Autolock autoLock(mLock);
-    mTextSourceVector.add(source);
+    mTextSourceVector.add(trackIndex, source);
+    mTextSourceTypeVector.add(false);
     return OK;
 }
 
-void TimedTextDriver::getTrackInfo(Parcel *parcel) {
+size_t TimedTextDriver::countExternalTracks() const {
+    size_t nTracks = 0;
+    for (size_t i = 0, n = mTextSourceTypeVector.size(); i < n; ++i) {
+        if (!mTextSourceTypeVector[i]) {
+            ++nTracks;
+        }
+    }
+    return nTracks;
+}
+
+void TimedTextDriver::getExternalTrackInfo(Parcel *parcel) {
     Mutex::Autolock autoLock(mLock);
-    Vector<sp<TimedTextSource> >::const_iterator iter;
-    parcel->writeInt32(mTextSourceVector.size());
-    for (iter = mTextSourceVector.begin();
-         iter != mTextSourceVector.end(); ++iter) {
-        sp<MetaData> meta = (*iter)->getFormat();
+    for (size_t i = 0, n = mTextSourceTypeVector.size(); i < n; ++i) {
+        if (mTextSourceTypeVector[i]) {
+            continue;
+        }
+
+        sp<MetaData> meta = mTextSourceVector.valueAt(i)->getFormat();
 
         // There are two fields.
         parcel->writeInt32(2);
 
         // track type.
         parcel->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT);
-
         const char *lang = "und";
         if (meta != NULL) {
             meta->findCString(kKeyMediaLanguage, &lang);
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 2cf77ce..d52ed42 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -34,6 +34,8 @@
 #   AudioResamplerSinc.cpp.arm
 #   AudioResamplerCubic.cpp.arm
 
+LOCAL_SRC_FILES += StateQueue.cpp
+
 LOCAL_C_INCLUDES := \
     $(call include-path-for, audio-effects) \
     $(call include-path-for, audio-utils)
@@ -60,4 +62,10 @@
 
 LOCAL_MODULE:= libaudioflinger
 
+LOCAL_SRC_FILES += FastMixer.cpp FastMixerState.cpp
+
+#LOCAL_CFLAGS += -DFAST_MIXER_STATISTICS
+
+LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"'
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9b4fb7a..99dcf45 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -138,25 +138,31 @@
 }
 #endif
 
-static int load_audio_interface(const char *if_name, const hw_module_t **mod,
-                                audio_hw_device_t **dev)
+static int load_audio_interface(const char *if_name, audio_hw_device_t **dev)
 {
+    const hw_module_t *mod;
     int rc;
 
-    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, mod);
-    if (rc)
+    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
+    ALOGE_IF(rc, "%s couldn't load audio hw module %s.%s (%s)", __func__,
+                 AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
+    if (rc) {
         goto out;
-
-    rc = audio_hw_device_open(*mod, dev);
-    ALOGE_IF(rc, "couldn't open audio hw device in %s.%s (%s)",
-            AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
-    if (rc)
+    }
+    rc = audio_hw_device_open(mod, dev);
+    ALOGE_IF(rc, "%s couldn't open audio hw device in %s.%s (%s)", __func__,
+                 AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
+    if (rc) {
         goto out;
-
+    }
+    if ((*dev)->common.version != AUDIO_DEVICE_API_VERSION_CURRENT) {
+        ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
+        rc = BAD_VALUE;
+        goto out;
+    }
     return 0;
 
 out:
-    *mod = NULL;
     *dev = NULL;
     return rc;
 }
@@ -914,7 +920,12 @@
 
     AutoMutex lock(mHardwareLock);
     mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE;
-    size_t size = mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, sampleRate, format, channelCount);
+    struct audio_config config = {
+        sample_rate: sampleRate,
+        channel_mask: audio_channel_in_mask_from_count(channelCount),
+        format: format,
+    };
+    size_t size = mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, &config);
     mHardwareStatus = AUDIO_HW_IDLE;
     return size;
 }
@@ -1597,7 +1608,7 @@
             // FIXME test that MixerThread for this fast track has a capable output HAL
             // FIXME add a permission test also?
           ) ) {
-        ALOGW("AUDIO_POLICY_OUTPUT_FLAG_FAST denied");
+        ALOGW("AUDIO_OUTPUT_FLAG_FAST denied");
         flags &= ~IAudioFlinger::TRACK_FAST;
     }
 
@@ -2653,13 +2664,7 @@
 // getTrackName_l() must be called with ThreadBase::mLock held
 int AudioFlinger::MixerThread::getTrackName_l(audio_channel_mask_t channelMask)
 {
-    int name = mAudioMixer->getTrackName();
-    if (name >= 0) {
-        mAudioMixer->setParameter(name,
-                AudioMixer::TRACK,
-                AudioMixer::CHANNEL_MASK, (void *)channelMask);
-    }
-    return name;
+    return mAudioMixer->getTrackName(channelMask);
 }
 
 // deleteTrackName_l() must be called with ThreadBase::mLock held
@@ -3496,14 +3501,12 @@
     int8_t *bufferEnd = bufferStart + frames * frameSize;
 
     // Check validity of returned pointer in case the track control block would have been corrupted.
-    if (bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd ||
-        ((unsigned long)bufferStart & (unsigned long)(frameSize - 1))) {
-        ALOGE("TrackBase::getBuffer buffer out of range:\n    start: %p, end %p , mBuffer %p mBufferEnd %p\n    \
-                server %u, serverBase %u, user %u, userBase %u",
+    ALOG_ASSERT(!(bufferStart < mBuffer || bufferStart > bufferEnd || bufferEnd > mBufferEnd),
+            "TrackBase::getBuffer buffer out of range:\n"
+                "    start: %p, end %p , mBuffer %p mBufferEnd %p\n"
+                "    server %u, serverBase %u, user %u, userBase %u, frameSize %d",
                 bufferStart, bufferEnd, mBuffer, mBufferEnd,
-                cblk->server, cblk->serverBase, cblk->user, cblk->userBase);
-        return NULL;
-    }
+                cblk->server, cblk->serverBase, cblk->user, cblk->userBase, frameSize);
 
     return bufferStart;
 }
@@ -3687,7 +3690,7 @@
             mName, IPCThreadState::self()->getCallingPid(), mSessionId, tid);
     // check for use case 2 with missing callback
     if (isFastTrack() && (mSharedBuffer == 0) && (tid == 0)) {
-        ALOGW("AUDIO_POLICY_OUTPUT_FLAG_FAST denied");
+        ALOGW("AUDIO_OUTPUT_FLAG_FAST denied");
         mFlags &= ~IAudioFlinger::TRACK_FAST;
         // FIXME the track must be invalidated and moved to another thread or
         // attached directly to the normal mixer now
@@ -4045,11 +4048,11 @@
     uint32_t bufBytes        = buf.buffer()->size();
     uint32_t consumedAlready = buf.position();
 
-    ALOG_ASSERT(consumedAlready <= bufFrames,
+    ALOG_ASSERT(consumedAlready <= bufBytes,
                 "Bad bookkeeping while updating frames pending.  Timed buffer is"
                 " only %u bytes long, but claims to have consumed %u"
                 " bytes.  (update reason: \"%s\")",
-                bufFrames, consumedAlready, logTag);
+                bufBytes, consumedAlready, logTag);
 
     uint32_t bufFrames = (bufBytes - consumedAlready) / mCblk->frameSize;
     ALOG_ASSERT(mFramesPendingInQueue >= bufFrames,
@@ -5743,10 +5746,9 @@
         }
     }
 
-    const hw_module_t *mod;
     audio_hw_device_t *dev;
 
-    int rc = load_audio_interface(name, &mod, &dev);
+    int rc = load_audio_interface(name, &dev);
     if (rc) {
         ALOGI("loadHwModule() error %d loading module %s ", rc, name);
         return 0;
@@ -5772,7 +5774,7 @@
     mAudioHwDevs.add(handle, new AudioHwDevice(name, dev));
 
     ALOGI("loadHwModule() Loaded %s audio interface from %s (%s) handle %d",
-          name, mod->name, mod->id, handle);
+          name, dev->common.module->name, dev->common.module->id, handle);
 
     return handle;
 
@@ -5784,23 +5786,24 @@
                                            audio_format_t *pFormat,
                                            audio_channel_mask_t *pChannelMask,
                                            uint32_t *pLatencyMs,
-                                           audio_policy_output_flags_t flags)
+                                           audio_output_flags_t flags)
 {
     status_t status;
     PlaybackThread *thread = NULL;
-    uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
-    audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT;
-    audio_channel_mask_t channelMask = pChannelMask ? *pChannelMask : 0;
-    uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
-    audio_stream_out_t *outStream;
+    struct audio_config config = {
+        sample_rate: pSamplingRate ? *pSamplingRate : 0,
+        channel_mask: pChannelMask ? *pChannelMask : 0,
+        format: pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT,
+    };
+    audio_stream_out_t *outStream = NULL;
     audio_hw_device_t *outHwDev;
 
     ALOGV("openOutput(), module %d Device %x, SamplingRate %d, Format %d, Channels %x, flags %x",
               module,
               (pDevices != NULL) ? (int)*pDevices : 0,
-              samplingRate,
-              format,
-              channelMask,
+              config.sample_rate,
+              config.format,
+              config.channel_mask,
               flags);
 
     if (pDevices == NULL || *pDevices == 0) {
@@ -5813,24 +5816,31 @@
     if (outHwDev == NULL)
         return 0;
 
+    audio_io_handle_t id = nextUniqueId();
+
     mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
-    status = outHwDev->open_output_stream(outHwDev, *pDevices, &format,
-                                          &channelMask, &samplingRate, &outStream);
+
+    status = outHwDev->open_output_stream(outHwDev,
+                                          id,
+                                          *pDevices,
+                                          (audio_output_flags_t)flags,
+                                          &config,
+                                          &outStream);
+
     mHardwareStatus = AUDIO_HW_IDLE;
     ALOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %d, Channels %x, status %d",
             outStream,
-            samplingRate,
-            format,
-            channelMask,
+            config.sample_rate,
+            config.format,
+            config.channel_mask,
             status);
 
-    if (outStream != NULL) {
+    if (status == NO_ERROR && outStream != NULL) {
         AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream);
-        audio_io_handle_t id = nextUniqueId();
 
-        if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) ||
-            (format != AUDIO_FORMAT_PCM_16_BIT) ||
-            (channelMask != AUDIO_CHANNEL_OUT_STEREO)) {
+        if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) ||
+            (config.format != AUDIO_FORMAT_PCM_16_BIT) ||
+            (config.channel_mask != AUDIO_CHANNEL_OUT_STEREO)) {
             thread = new DirectOutputThread(this, output, id, *pDevices);
             ALOGV("openOutput() created direct output: ID %d thread %p", id, thread);
         } else {
@@ -5839,16 +5849,16 @@
         }
         mPlaybackThreads.add(id, thread);
 
-        if (pSamplingRate != NULL) *pSamplingRate = samplingRate;
-        if (pFormat != NULL) *pFormat = format;
-        if (pChannelMask != NULL) *pChannelMask = channelMask;
+        if (pSamplingRate != NULL) *pSamplingRate = config.sample_rate;
+        if (pFormat != NULL) *pFormat = config.format;
+        if (pChannelMask != NULL) *pChannelMask = config.channel_mask;
         if (pLatencyMs != NULL) *pLatencyMs = thread->latency();
 
         // notify client processes of the new output creation
         thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
 
         // the first primary output opened designates the primary hw device
-        if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_POLICY_OUTPUT_FLAG_PRIMARY)) {
+        if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
             ALOGI("Using module %d has the primary audio interface", module);
             mPrimaryHardwareDev = outHwDev;
 
@@ -5995,13 +6005,15 @@
 {
     status_t status;
     RecordThread *thread = NULL;
-    uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
-    audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT;
-    audio_channel_mask_t channelMask = pChannelMask ? *pChannelMask : 0;
-    uint32_t reqSamplingRate = samplingRate;
-    audio_format_t reqFormat = format;
-    audio_channel_mask_t reqChannels = channelMask;
-    audio_stream_in_t *inStream;
+    struct audio_config config = {
+        sample_rate: pSamplingRate ? *pSamplingRate : 0,
+        channel_mask: pChannelMask ? *pChannelMask : 0,
+        format: pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT,
+    };
+    uint32_t reqSamplingRate = config.sample_rate;
+    audio_format_t reqFormat = config.format;
+    audio_channel_mask_t reqChannels = config.channel_mask;
+    audio_stream_in_t *inStream = NULL;
     audio_hw_device_t *inHwDev;
 
     if (pDevices == NULL || *pDevices == 0) {
@@ -6014,35 +6026,32 @@
     if (inHwDev == NULL)
         return 0;
 
-    status = inHwDev->open_input_stream(inHwDev, *pDevices, &format,
-                                        &channelMask, &samplingRate,
-                                        (audio_in_acoustics_t)0,
+    audio_io_handle_t id = nextUniqueId();
+
+    status = inHwDev->open_input_stream(inHwDev, id, *pDevices, &config,
                                         &inStream);
     ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, status %d",
             inStream,
-            samplingRate,
-            format,
-            channelMask,
+            config.sample_rate,
+            config.format,
+            config.channel_mask,
             status);
 
     // If the input could not be opened with the requested parameters and we can handle the conversion internally,
     // try to open again with the proposed parameters. The AudioFlinger can resample the input and do mono to stereo
     // or stereo to mono conversions on 16 bit PCM inputs.
-    if (inStream == NULL && status == BAD_VALUE &&
-        reqFormat == format && format == AUDIO_FORMAT_PCM_16_BIT &&
-        (samplingRate <= 2 * reqSamplingRate) &&
-        (popcount(channelMask) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) {
+    if (status == BAD_VALUE &&
+        reqFormat == config.format && config.format == AUDIO_FORMAT_PCM_16_BIT &&
+        (config.sample_rate <= 2 * reqSamplingRate) &&
+        (popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) {
         ALOGV("openInput() reopening with proposed sampling rate and channels");
-        status = inHwDev->open_input_stream(inHwDev, *pDevices, &format,
-                                            &channelMask, &samplingRate,
-                                            (audio_in_acoustics_t)0,
-                                            &inStream);
+        inStream = NULL;
+        status = inHwDev->open_input_stream(inHwDev, id, *pDevices, &config, &inStream);
     }
 
-    if (inStream != NULL) {
+    if (status == NO_ERROR && inStream != NULL) {
         AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream);
 
-        audio_io_handle_t id = nextUniqueId();
         // Start record thread
         // RecorThread require both input and output device indication to forward to audio
         // pre processing modules
@@ -6056,7 +6065,7 @@
         mRecordThreads.add(id, thread);
         ALOGV("openInput() created record thread: ID %d thread %p", id, thread);
         if (pSamplingRate != NULL) *pSamplingRate = reqSamplingRate;
-        if (pFormat != NULL) *pFormat = format;
+        if (pFormat != NULL) *pFormat = config.format;
         if (pChannelMask != NULL) *pChannelMask = reqChannels;
 
         input->stream->common.standby(&input->stream->common);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 9e6201a..b1c5554 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -144,7 +144,7 @@
                                          audio_format_t *pFormat,
                                          audio_channel_mask_t *pChannelMask,
                                          uint32_t *pLatencyMs,
-                                         audio_policy_output_flags_t flags);
+                                         audio_output_flags_t flags);
 
     virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
                                                   audio_io_handle_t output2);
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 399d987..0c8b3ce 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -69,7 +69,7 @@
 
             res = (*mDownmixHandle)->process(mDownmixHandle,
                     &mDownmixConfig.inputCfg.buffer, &mDownmixConfig.outputCfg.buffer);
-            ALOGV("getNextBuffer is downmixing");
+            //ALOGV("getNextBuffer is downmixing");
         }
         return res;
     } else {
@@ -79,7 +79,7 @@
 }
 
 void AudioMixer::DownmixerBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) {
-    ALOGV("DownmixerBufferProvider::releaseBuffer()");
+    //ALOGV("DownmixerBufferProvider::releaseBuffer()");
     if (this->mTrackBufferProvider != NULL) {
         mTrackBufferProvider->releaseBuffer(pBuffer);
     } else {
@@ -98,7 +98,7 @@
 {
     // AudioMixer is not yet capable of multi-channel beyond stereo
     COMPILE_TIME_ASSERT_FUNCTION_SCOPE(2 == MAX_NUM_CHANNELS);
-    
+
     ALOG_ASSERT(maxNumTracks <= MAX_NUM_TRACKS, "maxNumTracks %u > MAX_NUM_TRACKS %u",
             maxNumTracks, MAX_NUM_TRACKS);
 
@@ -119,6 +119,8 @@
     for (unsigned i=0 ; i < MAX_NUM_TRACKS ; i++) {
         // FIXME redundant per track
         t->localTimeFreq = lc.getLocalFreq();
+        t->resampler = NULL;
+        t->downmixerBufferProvider = NULL;
         t++;
     }
 
@@ -150,13 +152,14 @@
     track_t* t = mState.tracks;
     for (unsigned i=0 ; i < MAX_NUM_TRACKS ; i++) {
         delete t->resampler;
+        delete t->downmixerBufferProvider;
         t++;
     }
     delete [] mState.outputTemp;
     delete [] mState.resampleTemp;
 }
 
-int AudioMixer::getTrackName()
+int AudioMixer::getTrackName(audio_channel_mask_t channelMask)
 {
     uint32_t names = (~mTrackNames) & mConfiguredNames;
     if (names != 0) {
@@ -196,7 +199,13 @@
         t->mainBuffer = NULL;
         t->auxBuffer = NULL;
         // see t->localTimeFreq in constructor above
-        return TRACK0 + n;
+
+        status_t status = initTrackDownmix(&mState.tracks[n], n, channelMask);
+        if (status == OK) {
+            return TRACK0 + n;
+        }
+        ALOGE("AudioMixer::getTrackName(0x%x) failed, error preparing track for downmix",
+                channelMask);
     }
     return -1;
 }
@@ -209,16 +218,43 @@
     }
  }
 
+status_t AudioMixer::initTrackDownmix(track_t* pTrack, int trackNum, audio_channel_mask_t mask)
+{
+    uint32_t channelCount = popcount(mask);
+    ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount);
+    status_t status = OK;
+    if (channelCount > MAX_NUM_CHANNELS) {
+        pTrack->channelMask = mask;
+        pTrack->channelCount = channelCount;
+        ALOGV("initTrackDownmix(track=%d, mask=0x%x) calls prepareTrackForDownmix()",
+                trackNum, mask);
+        status = prepareTrackForDownmix(pTrack, trackNum);
+    } else {
+        unprepareTrackForDownmix(pTrack, trackNum);
+    }
+    return status;
+}
+
+void AudioMixer::unprepareTrackForDownmix(track_t* pTrack, int trackName) {
+    ALOGV("AudioMixer::unprepareTrackForDownmix(%d)", trackName);
+
+    if (pTrack->downmixerBufferProvider != NULL) {
+        // this track had previously been configured with a downmixer, delete it
+        ALOGV(" deleting old downmixer");
+        pTrack->bufferProvider = pTrack->downmixerBufferProvider->mTrackBufferProvider;
+        delete pTrack->downmixerBufferProvider;
+        pTrack->downmixerBufferProvider = NULL;
+    } else {
+        ALOGV(" nothing to do, no downmixer to delete");
+    }
+}
+
 status_t AudioMixer::prepareTrackForDownmix(track_t* pTrack, int trackName)
 {
     ALOGV("AudioMixer::prepareTrackForDownmix(%d) with mask 0x%x", trackName, pTrack->channelMask);
 
-    if (pTrack->downmixerBufferProvider != NULL) {
-        // this track had previously been configured with a downmixer, reset it
-        ALOGV("AudioMixer::prepareTrackForDownmix(%d) deleting old downmixer", trackName);
-        pTrack->bufferProvider = pTrack->downmixerBufferProvider->mTrackBufferProvider;
-        delete pTrack->downmixerBufferProvider;
-    }
+    // discard the previous downmixer if there was one
+    unprepareTrackForDownmix(pTrack, trackName);
 
     DownmixerBufferProvider* pDbp = new DownmixerBufferProvider();
     int32_t status;
@@ -318,6 +354,7 @@
 
 void AudioMixer::deleteTrackName(int name)
 {
+    ALOGV("AudioMixer::deleteTrackName(%d)", name);
     name -= TRACK0;
     ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name);
     ALOGV("deleteTrackName(%d)", name);
@@ -326,15 +363,12 @@
         track.enabled = false;
         invalidateState(1<<name);
     }
-    if (track.resampler != NULL) {
-        // delete the resampler
-        delete track.resampler;
-        track.resampler = NULL;
-        track.sampleRate = mSampleRate;
-        invalidateState(1<<name);
-    }
-    track.volumeInc[0] = 0;
-    track.volumeInc[1] = 0;
+    // delete the resampler
+    delete track.resampler;
+    track.resampler = NULL;
+    // delete the downmixer
+    unprepareTrackForDownmix(&mState.tracks[name], name);
+
     mTrackNames &= ~(1<<name);
 }
 
@@ -358,11 +392,6 @@
     track_t& track = mState.tracks[name];
 
     if (track.enabled) {
-        if (track.downmixerBufferProvider != NULL) {
-            ALOGV("AudioMixer::disable(%d) deleting downmixerBufferProvider", name);
-            delete track.downmixerBufferProvider;
-            track.downmixerBufferProvider = NULL;
-        }
         track.enabled = false;
         ALOGV("disable(%d)", name);
         invalidateState(1 << name);
@@ -389,11 +418,8 @@
                 ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount);
                 track.channelMask = mask;
                 track.channelCount = channelCount;
-                if (channelCount > MAX_NUM_CHANNELS) {
-                    ALOGV("AudioMixer::setParameter(TRACK, CHANNEL_MASK, mask=0x%x count=%d)",
-                            mask, channelCount);
-                    status_t status = prepareTrackForDownmix(&mState.tracks[name], name);
-                }
+                // the mask has changed, does this track need a downmixer?
+                initTrackDownmix(&mState.tracks[name], name, mask);
                 ALOGV("setParameter(TRACK, CHANNEL_MASK, %x)", mask);
                 invalidateState(1 << name);
             }
@@ -438,6 +464,12 @@
             track.resetResampler();
             invalidateState(1 << name);
             break;
+        case REMOVE:
+            delete track.resampler;
+            track.resampler = NULL;
+            track.sampleRate = mSampleRate;
+            invalidateState(1 << name);
+            break;
         default:
             LOG_FATAL("bad param");
         }
@@ -498,12 +530,15 @@
 
 bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
 {
-    if (value!=devSampleRate || resampler) {
+    if (value != devSampleRate || resampler != NULL) {
         if (sampleRate != value) {
             sampleRate = value;
             if (resampler == NULL) {
                 resampler = AudioResampler::create(
-                        format, channelCount, devSampleRate);
+                        format,
+                        // the resampler sees the number of channels after the downmixer, if any
+                        downmixerBufferProvider != NULL ? MAX_NUM_CHANNELS : channelCount,
+                        devSampleRate);
                 resampler->setLocalTimeFreq(localTimeFreq);
             }
             return true;
@@ -629,7 +664,7 @@
                 resampling = true;
                 t.hook = track__genericResample;
                 ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2,
-                        "Track needs downmix + resample");
+                        "Track %d needs downmix + resample", i);
             } else {
                 if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
                     t.hook = track__16BitsMono;
@@ -638,7 +673,7 @@
                 if ((n & NEEDS_CHANNEL_COUNT__MASK) >= NEEDS_CHANNEL_2){
                     t.hook = track__16BitsStereo;
                     ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2,
-                            "Track needs downmix");
+                            "Track %d needs downmix", i);
                 }
             }
         }
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index a04fe95..46deae7 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -70,8 +70,17 @@
         AUX_BUFFER      = 0x4003,
         DOWNMIX_TYPE    = 0X4004,
         // for target RESAMPLE
-        SAMPLE_RATE     = 0x4100,
-        RESET           = 0x4101,
+        SAMPLE_RATE     = 0x4100, // Configure sample rate conversion on this track name;
+                                  // parameter 'value' is the new sample rate in Hz.
+                                  // Only creates a sample rate converter the first time that
+                                  // the track sample rate is different from the mix sample rate.
+                                  // If the new sample rate is the same as the mix sample rate,
+                                  // and a sample rate converter already exists,
+                                  // then the sample rate converter remains present but is a no-op.
+        RESET           = 0x4101, // Reset sample rate converter without changing sample rate.
+                                  // This clears out the resampler's input buffer.
+        REMOVE          = 0x4102, // Remove the sample rate converter on this track name;
+                                  // the track is restored to the mix sample rate.
         // for target RAMP_VOLUME and VOLUME (8 channels max)
         VOLUME0         = 0x4200,
         VOLUME1         = 0x4201,
@@ -82,7 +91,7 @@
     // For all APIs with "name": TRACK0 <= name < TRACK0 + MAX_NUM_TRACKS
 
     // Allocate a track name.  Returns new track name if successful, -1 on failure.
-    int         getTrackName();
+    int         getTrackName(audio_channel_mask_t channelMask);
 
     // Free an allocated track by name
     void        deleteTrackName(int name);
@@ -237,8 +246,13 @@
     // indicates whether a downmix effect has been found and is usable by this mixer
     static bool                isMultichannelCapable;
 
+    // Call after changing either the enabled status of a track, or parameters of an enabled track.
+    // OK to call more often than that, but unnecessary.
     void invalidateState(uint32_t mask);
+
+    static status_t initTrackDownmix(track_t* pTrack, int trackNum, audio_channel_mask_t mask);
     static status_t prepareTrackForDownmix(track_t* pTrack, int trackNum);
+    static void unprepareTrackForDownmix(track_t* pTrack, int trackName);
 
     static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
     static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 15f4349..ca25ba9 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -224,7 +224,7 @@
                                     uint32_t samplingRate,
                                     audio_format_t format,
                                     uint32_t channels,
-                                    audio_policy_output_flags_t flags)
+                                    audio_output_flags_t flags)
 {
     if (mpAudioPolicy == NULL) {
         return 0;
@@ -1349,7 +1349,7 @@
                                          audio_format_t *pFormat,
                                          audio_channel_mask_t *pChannelMask,
                                          uint32_t *pLatencyMs,
-                                         audio_policy_output_flags_t flags)
+                                         audio_output_flags_t flags)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
@@ -1368,7 +1368,7 @@
                                                    audio_format_t *pFormat,
                                                    audio_channel_mask_t *pChannelMask,
                                                    uint32_t *pLatencyMs,
-                                                   audio_policy_output_flags_t flags)
+                                                   audio_output_flags_t flags)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index 9ed905d..fbca000 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -65,8 +65,8 @@
                                         uint32_t samplingRate = 0,
                                         audio_format_t format = AUDIO_FORMAT_DEFAULT,
                                         uint32_t channels = 0,
-                                        audio_policy_output_flags_t flags =
-                                                AUDIO_POLICY_OUTPUT_FLAG_NONE);
+                                        audio_output_flags_t flags =
+                                                AUDIO_OUTPUT_FLAG_NONE);
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
                                  int session = 0);
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
new file mode 100644
index 0000000..14954f7
--- /dev/null
+++ b/services/audioflinger/FastMixer.cpp
@@ -0,0 +1,455 @@
+/*
+ * 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_TAG "FastMixer"
+//#define LOG_NDEBUG 0
+
+#include <sys/atomics.h>
+#include <time.h>
+#include <utils/Log.h>
+#include <system/audio.h>
+#ifdef FAST_MIXER_STATISTICS
+#include <cpustats/CentralTendencyStatistics.h>
+#endif
+#include "AudioMixer.h"
+#include "FastMixer.h"
+
+#define FAST_HOT_IDLE_NS     1000000L   // 1 ms: time to sleep while hot idling
+#define FAST_DEFAULT_NS    999999999L   // ~1 sec: default time to sleep
+
+namespace android {
+
+// Fast mixer thread
+bool FastMixer::threadLoop()
+{
+    static const FastMixerState initial;
+    const FastMixerState *previous = &initial, *current = &initial;
+    FastMixerState preIdle; // copy of state before we went into idle
+    struct timespec oldTs = {0, 0};
+    bool oldTsValid = false;
+    long slopNs = 0;    // accumulated time we've woken up too early (> 0) or too late (< 0)
+    long sleepNs = -1;  // -1: busy wait, 0: sched_yield, > 0: nanosleep
+    int fastTrackNames[FastMixerState::kMaxFastTracks]; // handles used by mixer to identify tracks
+    int generations[FastMixerState::kMaxFastTracks];    // last observed mFastTracks[i].mGeneration
+    unsigned i;
+    for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
+        fastTrackNames[i] = -1;
+        generations[i] = 0;
+    }
+    NBAIO_Sink *outputSink = NULL;
+    int outputSinkGen = 0;
+    AudioMixer* mixer = NULL;
+    short *mixBuffer = NULL;
+    enum {UNDEFINED, MIXED, ZEROED} mixBufferState = UNDEFINED;
+    NBAIO_Format format = Format_Invalid;
+    unsigned sampleRate = 0;
+    int fastTracksGen = 0;
+    long periodNs = 0;      // expected period; the time required to render one mix buffer
+    long underrunNs = 0;    // an underrun is likely if an actual cycle is greater than this value
+    long overrunNs = 0;     // an overrun is likely if an actual cycle if less than this value
+    FastMixerDumpState dummyDumpState, *dumpState = &dummyDumpState;
+    bool ignoreNextOverrun = true;  // used to ignore initial overrun and first after an underrun
+#ifdef FAST_MIXER_STATISTICS
+    CentralTendencyStatistics cts;  // cycle times in seconds
+    static const unsigned kMaxSamples = 1000;
+#endif
+    unsigned coldGen = 0;   // last observed mColdGen
+
+    for (;;) {
+
+        // either nanosleep, sched_yield, or busy wait
+        if (sleepNs >= 0) {
+            if (sleepNs > 0) {
+                ALOG_ASSERT(sleepNs < 1000000000);
+                const struct timespec req = {0, sleepNs};
+                nanosleep(&req, NULL);
+            } else {
+                sched_yield();
+            }
+        }
+        // default to long sleep for next cycle
+        sleepNs = FAST_DEFAULT_NS;
+
+        // poll for state change
+        const FastMixerState *next = mSQ.poll();
+        if (next == NULL) {
+            // continue to use the default initial state until a real state is available
+            ALOG_ASSERT(current == &initial && previous == &initial);
+            next = current;
+        }
+
+        FastMixerState::Command command = next->mCommand;
+        if (next != current) {
+
+            // As soon as possible of learning of a new dump area, start using it
+            dumpState = next->mDumpState != NULL ? next->mDumpState : &dummyDumpState;
+
+            // We want to always have a valid reference to the previous (non-idle) state.
+            // However, the state queue only guarantees access to current and previous states.
+            // So when there is a transition from a non-idle state into an idle state, we make a
+            // copy of the last known non-idle state so it is still available on return from idle.
+            // The possible transitions are:
+            //  non-idle -> non-idle    update previous from current in-place
+            //  non-idle -> idle        update previous from copy of current
+            //  idle     -> idle        don't update previous
+            //  idle     -> non-idle    don't update previous
+            if (!(current->mCommand & FastMixerState::IDLE)) {
+                if (command & FastMixerState::IDLE) {
+                    preIdle = *current;
+                    current = &preIdle;
+                    oldTsValid = false;
+                    ignoreNextOverrun = true;
+                }
+                previous = current;
+            }
+            current = next;
+        }
+#if !LOG_NDEBUG
+        next = NULL;    // not referenced again
+#endif
+
+        dumpState->mCommand = command;
+
+        switch (command) {
+        case FastMixerState::INITIAL:
+        case FastMixerState::HOT_IDLE:
+            sleepNs = FAST_HOT_IDLE_NS;
+            continue;
+        case FastMixerState::COLD_IDLE:
+            // only perform a cold idle command once
+            if (current->mColdGen != coldGen) {
+                int32_t *coldFutexAddr = current->mColdFutexAddr;
+                ALOG_ASSERT(coldFutexAddr != NULL);
+                int32_t old = android_atomic_dec(coldFutexAddr);
+                if (old <= 0) {
+                    __futex_syscall4(coldFutexAddr, FUTEX_WAIT_PRIVATE, old - 1, NULL);
+                }
+                sleepNs = -1;
+                coldGen = current->mColdGen;
+            } else {
+                sleepNs = FAST_HOT_IDLE_NS;
+            }
+            continue;
+        case FastMixerState::EXIT:
+            delete mixer;
+            delete[] mixBuffer;
+            return false;
+        case FastMixerState::MIX:
+        case FastMixerState::WRITE:
+        case FastMixerState::MIX_WRITE:
+            break;
+        default:
+            LOG_FATAL("bad command %d", command);
+        }
+
+        // there is a non-idle state available to us; did the state change?
+        size_t frameCount = current->mFrameCount;
+        if (current != previous) {
+
+            // handle state change here, but since we want to diff the state,
+            // we're prepared for previous == &initial the first time through
+            unsigned previousTrackMask;
+
+            // check for change in output HAL configuration
+            NBAIO_Format previousFormat = format;
+            if (current->mOutputSinkGen != outputSinkGen) {
+                outputSink = current->mOutputSink;
+                outputSinkGen = current->mOutputSinkGen;
+                if (outputSink == NULL) {
+                    format = Format_Invalid;
+                    sampleRate = 0;
+                } else {
+                    format = outputSink->format();
+                    sampleRate = Format_sampleRate(format);
+                    ALOG_ASSERT(Format_channelCount(format) == 2);
+                }
+            }
+
+            if ((format != previousFormat) || (frameCount != previous->mFrameCount)) {
+                // FIXME to avoid priority inversion, don't delete here
+                delete mixer;
+                mixer = NULL;
+                delete[] mixBuffer;
+                mixBuffer = NULL;
+                if (frameCount > 0 && sampleRate > 0) {
+                    // FIXME new may block for unbounded time at internal mutex of the heap
+                    //       implementation; it would be better to have normal mixer allocate for us
+                    //       to avoid blocking here and to prevent possible priority inversion
+                    mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks);
+                    mixBuffer = new short[frameCount * 2];
+                    periodNs = (frameCount * 1000000000LL) / sampleRate;    // 1.00
+                    underrunNs = (frameCount * 1750000000LL) / sampleRate;  // 1.75
+                    overrunNs = (frameCount * 250000000LL) / sampleRate;    // 0.25
+                } else {
+                    periodNs = 0;
+                    underrunNs = 0;
+                    overrunNs = 0;
+                }
+                mixBufferState = UNDEFINED;
+#if !LOG_NDEBUG
+                for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
+                    fastTrackNames[i] = -1;
+                }
+#endif
+                // we need to reconfigure all active tracks
+                previousTrackMask = 0;
+                fastTracksGen = current->mFastTracksGen - 1;
+            } else {
+                previousTrackMask = previous->mTrackMask;
+            }
+
+            // check for change in active track set
+            unsigned currentTrackMask = current->mTrackMask;
+            if (current->mFastTracksGen != fastTracksGen) {
+                ALOG_ASSERT(mixBuffer != NULL);
+                int name;
+
+                // process removed tracks first to avoid running out of track names
+                unsigned removedTracks = previousTrackMask & ~currentTrackMask;
+                while (removedTracks != 0) {
+                    i = __builtin_ctz(removedTracks);
+                    removedTracks &= ~(1 << i);
+                    const FastTrack* fastTrack = &current->mFastTracks[i];
+                    if (mixer != NULL) {
+                        name = fastTrackNames[i];
+                        ALOG_ASSERT(name >= 0);
+                        mixer->deleteTrackName(name);
+                    }
+#if !LOG_NDEBUG
+                    fastTrackNames[i] = -1;
+#endif
+                    generations[i] = fastTrack->mGeneration;
+                }
+
+                // now process added tracks
+                unsigned addedTracks = currentTrackMask & ~previousTrackMask;
+                while (addedTracks != 0) {
+                    i = __builtin_ctz(addedTracks);
+                    addedTracks &= ~(1 << i);
+                    const FastTrack* fastTrack = &current->mFastTracks[i];
+                    AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
+                    ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1);
+                    if (mixer != NULL) {
+                        // calling getTrackName with default channel mask
+                        name = mixer->getTrackName(AUDIO_CHANNEL_OUT_STEREO);
+                        ALOG_ASSERT(name >= 0);
+                        fastTrackNames[i] = name;
+                        mixer->setBufferProvider(name, bufferProvider);
+                        mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
+                                (void *) mixBuffer);
+                        // newly allocated track names default to full scale volume
+                        mixer->enable(name);
+                    }
+                    generations[i] = fastTrack->mGeneration;
+                }
+
+                // finally process modified tracks; these use the same slot
+                // but may have a different buffer provider or volume provider
+                unsigned modifiedTracks = currentTrackMask & previousTrackMask;
+                while (modifiedTracks != 0) {
+                    i = __builtin_ctz(modifiedTracks);
+                    modifiedTracks &= ~(1 << i);
+                    const FastTrack* fastTrack = &current->mFastTracks[i];
+                    if (fastTrack->mGeneration != generations[i]) {
+                        AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
+                        ALOG_ASSERT(bufferProvider != NULL);
+                        if (mixer != NULL) {
+                            name = fastTrackNames[i];
+                            ALOG_ASSERT(name >= 0);
+                            mixer->setBufferProvider(name, bufferProvider);
+                            if (fastTrack->mVolumeProvider == NULL) {
+                                mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0,
+                                        (void *)0x1000);
+                                mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
+                                        (void *)0x1000);
+                            }
+                            // already enabled
+                        }
+                        generations[i] = fastTrack->mGeneration;
+                    }
+                }
+
+                fastTracksGen = current->mFastTracksGen;
+
+                dumpState->mNumTracks = popcount(currentTrackMask);
+            }
+
+#if 1   // FIXME shouldn't need this
+            // only process state change once
+            previous = current;
+#endif
+        }
+
+        // do work using current state here
+        if ((command & FastMixerState::MIX) && (mixer != NULL)) {
+            ALOG_ASSERT(mixBuffer != NULL);
+            // update volumes
+            unsigned volumeTracks = current->mTrackMask;
+            while (volumeTracks != 0) {
+                i = __builtin_ctz(volumeTracks);
+                volumeTracks &= ~(1 << i);
+                const FastTrack* fastTrack = &current->mFastTracks[i];
+                int name = fastTrackNames[i];
+                ALOG_ASSERT(name >= 0);
+                if (fastTrack->mVolumeProvider != NULL) {
+                    uint32_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
+                    mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0,
+                            (void *)(vlr & 0xFFFF));
+                    mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1,
+                            (void *)(vlr >> 16));
+                }
+            }
+            // process() is CPU-bound
+            mixer->process(AudioBufferProvider::kInvalidPTS);
+            mixBufferState = MIXED;
+        } else if (mixBufferState == MIXED) {
+            mixBufferState = UNDEFINED;
+        }
+        if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mixBuffer != NULL)) {
+            if (mixBufferState == UNDEFINED) {
+                memset(mixBuffer, 0, frameCount * 2 * sizeof(short));
+                mixBufferState = ZEROED;
+            }
+            // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
+            //       but this code should be modified to handle both non-blocking and blocking sinks
+            dumpState->mWriteSequence++;
+            ssize_t framesWritten = outputSink->write(mixBuffer, frameCount);
+            dumpState->mWriteSequence++;
+            if (framesWritten >= 0) {
+                dumpState->mFramesWritten += framesWritten;
+            } else {
+                dumpState->mWriteErrors++;
+            }
+            // FIXME count # of writes blocked excessively, CPU usage, etc. for dump
+        }
+
+        // To be exactly periodic, compute the next sleep time based on current time.
+        // This code doesn't have long-term stability when the sink is non-blocking.
+        // FIXME To avoid drift, use the local audio clock or watch the sink's fill status.
+        struct timespec newTs;
+        int rc = clock_gettime(CLOCK_MONOTONIC, &newTs);
+        if (rc == 0) {
+            if (oldTsValid) {
+                time_t sec = newTs.tv_sec - oldTs.tv_sec;
+                long nsec = newTs.tv_nsec - oldTs.tv_nsec;
+                if (nsec < 0) {
+                    --sec;
+                    nsec += 1000000000;
+                }
+                if (sec > 0 || nsec > underrunNs) {
+                    // FIXME only log occasionally
+                    ALOGV("underrun: time since last cycle %d.%03ld sec",
+                            (int) sec, nsec / 1000000L);
+                    dumpState->mUnderruns++;
+                    sleepNs = -1;
+                    ignoreNextOverrun = true;
+                } else if (nsec < overrunNs) {
+                    if (ignoreNextOverrun) {
+                        ignoreNextOverrun = false;
+                    } else {
+                        // FIXME only log occasionally
+                        ALOGV("overrun: time since last cycle %d.%03ld sec",
+                                (int) sec, nsec / 1000000L);
+                        dumpState->mOverruns++;
+                    }
+                    sleepNs = periodNs - overrunNs;
+                } else {
+                    sleepNs = -1;
+                    ignoreNextOverrun = false;
+                }
+#ifdef FAST_MIXER_STATISTICS
+                // long-term statistics
+                cts.sample(sec + nsec * 1e-9);
+                if (cts.n() >= kMaxSamples) {
+                    dumpState->mMean = cts.mean();
+                    dumpState->mMinimum = cts.minimum();
+                    dumpState->mMaximum = cts.maximum();
+                    dumpState->mStddev = cts.stddev();
+                    cts.reset();
+                }
+#endif
+            } else {
+                // first time through the loop
+                oldTsValid = true;
+                sleepNs = periodNs;
+                ignoreNextOverrun = true;
+            }
+            oldTs = newTs;
+        } else {
+            // monotonic clock is broken
+            oldTsValid = false;
+            sleepNs = periodNs;
+        }
+
+    }   // for (;;)
+
+    // never return 'true'; Thread::_threadLoop() locks mutex which can result in priority inversion
+}
+
+FastMixerDumpState::FastMixerDumpState() :
+    mCommand(FastMixerState::INITIAL), mWriteSequence(0), mFramesWritten(0),
+    mNumTracks(0), mWriteErrors(0), mUnderruns(0), mOverruns(0)
+#ifdef FAST_MIXER_STATISTICS
+    , mMean(0.0), mMinimum(0.0), mMaximum(0.0), mStddev(0.0)
+#endif
+{
+}
+
+FastMixerDumpState::~FastMixerDumpState()
+{
+}
+
+void FastMixerDumpState::dump(int fd)
+{
+#define COMMAND_MAX 32
+    char string[COMMAND_MAX];
+    switch (mCommand) {
+    case FastMixerState::INITIAL:
+        strcpy(string, "INITIAL");
+        break;
+    case FastMixerState::HOT_IDLE:
+        strcpy(string, "HOT_IDLE");
+        break;
+    case FastMixerState::COLD_IDLE:
+        strcpy(string, "COLD_IDLE");
+        break;
+    case FastMixerState::EXIT:
+        strcpy(string, "EXIT");
+        break;
+    case FastMixerState::MIX:
+        strcpy(string, "MIX");
+        break;
+    case FastMixerState::WRITE:
+        strcpy(string, "WRITE");
+        break;
+    case FastMixerState::MIX_WRITE:
+        strcpy(string, "MIX_WRITE");
+        break;
+    default:
+        snprintf(string, COMMAND_MAX, "%d", mCommand);
+        break;
+    }
+    fdprintf(fd, "FastMixer command=%s writeSequence=%u framesWritten=%u\n"
+                 "          numTracks=%u writeErrors=%u underruns=%u overruns=%u\n",
+                 string, mWriteSequence, mFramesWritten,
+                 mNumTracks, mWriteErrors, mUnderruns, mOverruns);
+#ifdef FAST_MIXER_STATISTICS
+    fdprintf(fd, "          cycle time in ms: mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
+                 mMean*1e3, mMinimum*1e3, mMaximum*1e3, mStddev*1e3);
+#endif
+}
+
+}   // namespace android
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
new file mode 100644
index 0000000..b24f2eb
--- /dev/null
+++ b/services/audioflinger/FastMixer.h
@@ -0,0 +1,72 @@
+/*
+ * 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 ANDROID_AUDIO_FAST_MIXER_H
+#define ANDROID_AUDIO_FAST_MIXER_H
+
+#include <utils/Thread.h>
+extern "C" {
+#include "../private/bionic_futex.h"
+}
+#include "StateQueue.h"
+#include "FastMixerState.h"
+
+namespace android {
+
+typedef StateQueue<FastMixerState> FastMixerStateQueue;
+
+class FastMixer : public Thread {
+
+public:
+            FastMixer() : Thread(false /*canCallJava*/) { }
+    virtual ~FastMixer() { }
+
+            FastMixerStateQueue* sq() { return &mSQ; }
+
+private:
+    virtual bool                threadLoop();
+            FastMixerStateQueue mSQ;
+
+};  // class FastMixer
+
+// The FastMixerDumpState keeps a cache of FastMixer statistics that can be logged by dumpsys.
+// Since used non-atomically, only POD types are permitted, and the contents can't be trusted.
+// It has a different lifetime than the FastMixer, and so it can't be a member of FastMixer.
+struct FastMixerDumpState {
+    FastMixerDumpState();
+    /*virtual*/ ~FastMixerDumpState();
+
+    void dump(int fd);
+
+    FastMixerState::Command mCommand;   // current command
+    uint32_t mWriteSequence;    // incremented before and after each write()
+    uint32_t mFramesWritten;    // total number of frames written successfully
+    uint32_t mNumTracks;        // total number of active fast tracks
+    uint32_t mWriteErrors;      // total number of write() errors
+    uint32_t mUnderruns;        // total number of underruns
+    uint32_t mOverruns;         // total number of overruns
+#ifdef FAST_MIXER_STATISTICS
+    // cycle times in seconds
+    float    mMean;
+    float    mMinimum;
+    float    mMaximum;
+    float    mStddev;
+#endif
+};
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_FAST_MIXER_H
diff --git a/services/audioflinger/FastMixerState.cpp b/services/audioflinger/FastMixerState.cpp
new file mode 100644
index 0000000..4eacacf
--- /dev/null
+++ b/services/audioflinger/FastMixerState.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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 "FastMixerState.h"
+
+namespace android {
+
+FastTrack::FastTrack() :
+    mBufferProvider(NULL), mVolumeProvider(NULL), mGeneration(0)
+{
+}
+
+FastTrack::~FastTrack()
+{
+}
+
+FastMixerState::FastMixerState() :
+    mFastTracksGen(0), mTrackMask(0), mOutputSink(NULL), mOutputSinkGen(0),
+    mFrameCount(0), mCommand(INITIAL), mColdFutexAddr(NULL), mColdGen(0), mDumpState(NULL)
+{
+}
+
+FastMixerState::~FastMixerState()
+{
+}
+
+}   // namespace android
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
new file mode 100644
index 0000000..64171ac
--- /dev/null
+++ b/services/audioflinger/FastMixerState.h
@@ -0,0 +1,80 @@
+/*
+ * 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 ANDROID_AUDIO_FAST_MIXER_STATE_H
+#define ANDROID_AUDIO_FAST_MIXER_STATE_H
+
+#include "AudioBufferProvider.h"
+#include "NBAIO.h"
+
+namespace android {
+
+struct FastMixerDumpState;
+
+class VolumeProvider {
+public:
+    // Return the track volume in U4_12 format: left in lower half, right in upper half. The
+    // provider implementation is responsible for validating that the return value is in range.
+    virtual uint32_t getVolumeLR() = 0;
+protected:
+    VolumeProvider() { }
+    virtual ~VolumeProvider() { }
+};
+
+// Represents the state of a fast track
+struct FastTrack {
+    FastTrack();
+    /*virtual*/ ~FastTrack();
+
+    AudioBufferProvider*    mBufferProvider; // must not be NULL
+    VolumeProvider*         mVolumeProvider; // optional; if NULL then full-scale
+    int                     mGeneration;     // increment when any field is assigned
+};
+
+// Represents a single state of the fast mixer
+struct FastMixerState {
+                FastMixerState();
+    /*virtual*/ ~FastMixerState();
+
+    static const unsigned kMaxFastTracks = 8;   // must be between 2 and 32 inclusive
+
+    // all pointer fields use raw pointers; objects are owned and ref-counted by the normal mixer
+    FastTrack   mFastTracks[kMaxFastTracks];
+    int         mFastTracksGen; // increment when any mFastTracks[i].mGeneration is incremented
+    unsigned    mTrackMask;     // bit i is set if and only if mFastTracks[i] != NULL
+    NBAIO_Sink* mOutputSink;    // HAL output device, must already be negotiated
+    int         mOutputSinkGen; // increment when mOutputSink is assigned
+    size_t      mFrameCount;    // number of frames per fast mix buffer
+    enum Command {
+        INITIAL = 0,            // used only for the initial state
+        HOT_IDLE = 1,           // do nothing
+        COLD_IDLE = 2,          // wait for the futex
+        IDLE = 3,               // either HOT_IDLE or COLD_IDLE
+        EXIT = 4,               // exit from thread
+        // The following commands also process configuration changes, and can be "or"ed:
+        MIX = 0x8,              // mix tracks
+        WRITE = 0x10,           // write to output sink
+        MIX_WRITE = 0x18,       // mix tracks and write to output sink
+    } mCommand;
+    int32_t*    mColdFutexAddr; // for COLD_IDLE only, pointer to the associated futex
+    unsigned    mColdGen;       // increment when COLD_IDLE is requested so it's only performed once
+    // This might be a one-time configuration rather than per-state
+    FastMixerDumpState* mDumpState; // if non-NULL, then update dump state periodically
+};  // struct FastMixerState
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_FAST_MIXER_STATE_H
diff --git a/services/audioflinger/StateQueue.cpp b/services/audioflinger/StateQueue.cpp
new file mode 100644
index 0000000..ae263f5
--- /dev/null
+++ b/services/audioflinger/StateQueue.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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_TAG "StateQueue"
+//#define LOG_NDEBUG 0
+
+#include <time.h>
+#include <cutils/atomic.h>
+#include <utils/Log.h>
+#include "StateQueue.h"
+
+namespace android {
+
+// Constructor and destructor
+
+template<typename T> StateQueue<T>::StateQueue() :
+    mNext(NULL), mAck(NULL), mCurrent(NULL),
+    mMutating(&mStates[0]), mExpecting(NULL),
+    mInMutation(false), mIsDirty(false), mIsInitialized(false)
+{
+}
+
+template<typename T> StateQueue<T>::~StateQueue()
+{
+}
+
+// Observer APIs
+
+template<typename T> const T* StateQueue<T>::poll()
+{
+    const T *next = (const T *) android_atomic_acquire_load((volatile int32_t *) &mNext);
+    if (next != mCurrent) {
+        mAck = next;    // no additional barrier needed
+        mCurrent = next;
+    }
+    return next;
+}
+
+// Mutator APIs
+
+template<typename T> T* StateQueue<T>::begin()
+{
+    ALOG_ASSERT(!mInMutation, "begin() called when in a mutation");
+    mInMutation = true;
+    return mMutating;
+}
+
+template<typename T> void StateQueue<T>::end(bool didModify)
+{
+    ALOG_ASSERT(mInMutation, "end() called when not in a mutation");
+    ALOG_ASSERT(mIsInitialized || didModify, "first end() must modify for initialization");
+    if (didModify) {
+        mIsDirty = true;
+        mIsInitialized = true;
+    }
+    mInMutation = false;
+}
+
+template<typename T> bool StateQueue<T>::push(StateQueue<T>::block_t block)
+{
+#define PUSH_BLOCK_ACK_NS    3000000L   // 3 ms: time between checks for ack in push()
+                                        //       FIXME should be configurable
+    static const struct timespec req = {0, PUSH_BLOCK_ACK_NS};
+
+    ALOG_ASSERT(!mInMutation, "push() called when in a mutation");
+
+    if (mIsDirty) {
+
+        // wait for prior push to be acknowledged
+        if (mExpecting != NULL) {
+            for (;;) {
+                const T *ack = (const T *) mAck;    // no additional barrier needed
+                if (ack == mExpecting) {
+                    // unnecessary as we're about to rewrite
+                    //mExpecting = NULL;
+                    break;
+                }
+                if (block == BLOCK_NEVER) {
+                    return false;
+                }
+                nanosleep(&req, NULL);
+            }
+        }
+
+        // publish
+        android_atomic_release_store((int32_t) mMutating, (volatile int32_t *) &mNext);
+        mExpecting = mMutating;
+
+        // copy with circular wraparound
+        if (++mMutating >= &mStates[kN]) {
+            mMutating = &mStates[0];
+        }
+        *mMutating = *mExpecting;
+        mIsDirty = false;
+
+    }
+
+    // optionally wait for this push or a prior push to be acknowledged
+    if (block == BLOCK_UNTIL_ACKED) {
+        if (mExpecting != NULL) {
+            for (;;) {
+                const T *ack = (const T *) mAck;    // no additional barrier needed
+                if (ack == mExpecting) {
+                    mExpecting = NULL;
+                    break;
+                }
+                nanosleep(&req, NULL);
+            }
+        }
+    }
+
+    return true;
+}
+
+}   // namespace android
+
+// hack for gcc
+#ifdef STATE_QUEUE_INSTANTIATIONS
+#include STATE_QUEUE_INSTANTIATIONS
+#endif
diff --git a/services/audioflinger/StateQueue.h b/services/audioflinger/StateQueue.h
new file mode 100644
index 0000000..fe72ddc
--- /dev/null
+++ b/services/audioflinger/StateQueue.h
@@ -0,0 +1,94 @@
+/*
+ * 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 ANDROID_AUDIO_STATE_QUEUE_H
+#define ANDROID_AUDIO_STATE_QUEUE_H
+
+namespace android {
+
+// manages a FIFO queue of states
+template<typename T> class StateQueue {
+
+public:
+            StateQueue();
+    virtual ~StateQueue();
+
+    // Observer APIs
+
+    // Poll for a state change.  Returns a pointer to a read-only state,
+    // or NULL if the state has not been initialized yet.
+    // If a new state has not pushed by mutator since the previous poll,
+    // then the returned pointer will be unchanged.
+    // The previous state pointer is guaranteed to still be valid;
+    // this allows the observer to diff the previous and new states.
+    const T* poll();
+
+    // Mutator APIs
+
+    // Begin a mutation.  Returns a pointer to a read/write state, except the
+    // first time it is called the state is write-only and _must_ be initialized.
+    // Mutations cannot be nested.
+    // If the state is dirty and has not been pushed onto the state queue yet, then
+    // this new mutation will be squashed together with the previous one.
+    T*      begin();
+
+    // End the current mutation and indicate whether caller modified the state.
+    // If didModify is true, then the state is marked dirty (in need of pushing).
+    // There is no rollback option because modifications are done in place.
+    // Does not automatically push the new state onto the state queue.
+    void    end(bool didModify = true);
+
+    // Push a new state, if any, out to the observer via the state queue.
+    // For BLOCK_NEVER, returns:
+    //      true if not dirty, or dirty and pushed successfully
+    //      false if dirty and not pushed because that would block; remains dirty
+    // For BLOCK_UNTIL_PUSHED and BLOCK_UNTIL_ACKED, always returns true.
+    // No-op if there are no pending modifications (not dirty), except
+    //      for BLOCK_UNTIL_ACKED it will wait until a prior push has been acknowledged.
+    // Must not be called in the middle of a mutation.
+    enum block_t {
+        BLOCK_NEVER,        // do not block
+        BLOCK_UNTIL_PUSHED, // block until there's a slot available for the push
+        BLOCK_UNTIL_ACKED,  // also block until the push is acknowledged by the observer
+    };
+    bool    push(block_t block = BLOCK_NEVER);
+
+    // Return whether the current state is dirty (modified and not pushed).
+    bool    isDirty() const { return mIsDirty; }
+
+private:
+    static const unsigned kN = 4;       // values != 4 are not supported by this code
+    T                 mStates[kN];      // written by mutator, read by observer
+
+    // "volatile" is meaningless with SMP, but here it indicates that we're using atomic ops
+    volatile const T* mNext; // written by mutator to advance next, read by observer
+    volatile const T* mAck;  // written by observer to acknowledge advance of next, read by mutator
+
+    // only used by observer
+    const T*          mCurrent;         // most recent value returned by poll()
+
+    // only used by mutator
+    T*                mMutating;        // where updates by mutator are done in place
+    const T*          mExpecting;       // what the mutator expects mAck to be set to
+    bool              mInMutation;      // whether we're currently in the middle of a mutation
+    bool              mIsDirty;         // whether mutating state has been modified since last push
+    bool              mIsInitialized;   // whether mutating state has been initialized yet
+
+};  // class StateQueue
+
+}   // namespace android
+
+#endif  // ANDROID_AUDIO_STATE_QUEUE_H
diff --git a/services/audioflinger/StateQueueInstantiations.cpp b/services/audioflinger/StateQueueInstantiations.cpp
new file mode 100644
index 0000000..077582f
--- /dev/null
+++ b/services/audioflinger/StateQueueInstantiations.cpp
@@ -0,0 +1,26 @@
+/*
+ * 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 "FastMixerState.h"
+#include "StateQueue.h"
+
+// FIXME hack for gcc
+
+namespace android {
+
+template class StateQueue<FastMixerState>;  // typedef FastMixerStateQueue
+
+}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index dc3f083..92d1223 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -21,7 +21,6 @@
 #include <stdio.h>
 #include <sys/types.h>
 #include <pthread.h>
-#include <time.h>
 
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -34,7 +33,6 @@
 #include <hardware/hardware.h>
 #include <media/AudioSystem.h>
 #include <media/mediaplayer.h>
-#include <utils/Condition.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/String16.h>
@@ -44,8 +42,6 @@
 
 namespace android {
 
-#define WAIT_RELEASE_TIMEOUT 250 // 250ms
-
 // ----------------------------------------------------------------------------
 // Logging support -- this is for debugging only
 // Use "adb shell dumpsys media.camera -v 1" to change it.
@@ -68,13 +64,6 @@
     return IPCThreadState::self()->getCallingUid();
 }
 
-static long long getTimeInMs() {
-    struct timeval t;
-    t.tv_sec = t.tv_usec = 0;
-    gettimeofday(&t, NULL);
-    return t.tv_sec * 1000LL + t.tv_usec / 1000;
-}
-
 // ----------------------------------------------------------------------------
 
 // This is ugly and only safe if we never re-create the CameraService, but
@@ -142,7 +131,7 @@
 }
 
 sp<ICamera> CameraService::connect(
-        const sp<ICameraClient>& cameraClient, int cameraId, bool force, bool keep) {
+        const sp<ICameraClient>& cameraClient, int cameraId) {
     int callingPid = getCallingPid();
     sp<CameraHardwareInterface> hardware = NULL;
 
@@ -168,73 +157,27 @@
         return NULL;
     }
 
-    if (keep && !checkCallingPermission(String16("android.permission.KEEP_CAMERA"))) {
-        ALOGE("connect X (pid %d) rejected (no KEEP_CAMERA permission).", callingPid);
-        return NULL;
-    }
-
     Mutex::Autolock lock(mServiceLock);
-    // Check if there is an existing client.
-    client = mClient[cameraId].promote();
-    if (client != 0 &&
-            cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
-        LOG1("connect X (pid %d) (the same client)", callingPid);
-        return client;
-    }
-
-    if (!force) {
-        if (mClient[cameraId].promote() != 0) {
-            ALOGW("connect X (pid %d) rejected (existing client).", callingPid);
-            return NULL;
-        }
-        mClient[cameraId].clear();
-        if (mBusy[cameraId]) {
-            ALOGW("connect X (pid %d) rejected (camera %d is still busy).",
-                  callingPid, cameraId);
-            return NULL;
-        }
-    } else { // force == true
-        int i = 0;
-        long long start_time = getTimeInMs();
-        while (i < mNumberOfCameras) {
-            if (getTimeInMs() - start_time >= 3000LL) {
-                ALOGE("connect X (pid %d) rejected (timeout 3s)", callingPid);
+    if (mClient[cameraId] != 0) {
+        client = mClient[cameraId].promote();
+        if (client != 0) {
+            if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
+                LOG1("CameraService::connect X (pid %d) (the same client)",
+                     callingPid);
+                return client;
+            } else {
+                ALOGW("CameraService::connect X (pid %d) rejected (existing client).",
+                      callingPid);
                 return NULL;
             }
-
-            client = mClient[i].promote();
-            if (client != 0) {
-                if (client->keep()) {
-                    ALOGW("connect X (pid %d) rejected (existing client wants to keeps the camera)",
-                          callingPid);
-                    return NULL;
-                } else {
-                    ALOGW("New client (pid %d, id=%d). Disconnect the existing client (id=%d).",
-                         callingPid, cameraId, i);
-                    // Do not hold mServiceLock because disconnect will try to get it.
-                    mServiceLock.unlock();
-                    client->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0, &i);
-                    client->waitRelease(WAIT_RELEASE_TIMEOUT);
-                    client->disconnectInternal(false);
-                    mServiceLock.lock();
-                    // Restart from the first client because a new client may have connected
-                    // when mServiceLock is unlocked.
-                    i = 0;
-                    continue;
-                }
-            }
-
-            if (mBusy[i]) {
-                // Give the client a chance to release the hardware.
-                mServiceLock.unlock();
-                usleep(10 * 1000);
-                mServiceLock.lock();
-                i = 0; // Restart from the first client
-                continue;
-            }
-
-            i++;
         }
+        mClient[cameraId].clear();
+    }
+
+    if (mBusy[cameraId]) {
+        ALOGW("CameraService::connect X (pid %d) rejected"
+                " (camera %d is still busy).", callingPid, cameraId);
+        return NULL;
     }
 
     struct camera_info info;
@@ -252,13 +195,7 @@
         return NULL;
     }
 
-    client = new Client(this, cameraClient, hardware, cameraId, info.facing,
-                        callingPid, keep);
-    // We need to clear the hardware here. After the destructor of mServiceLock
-    // finishes, a new client may connect and disconnect this client. If this
-    // reference is not cleared, the destructor of CameraHardwareInterface
-    // cannot run. The new client will not be able to connect.
-    hardware.clear();
+    client = new Client(this, cameraClient, hardware, cameraId, info.facing, callingPid);
     mClient[cameraId] = client;
     LOG1("CameraService::connect X (id %d)", cameraId);
     return client;
@@ -399,7 +336,7 @@
 CameraService::Client::Client(const sp<CameraService>& cameraService,
         const sp<ICameraClient>& cameraClient,
         const sp<CameraHardwareInterface>& hardware,
-        int cameraId, int cameraFacing, int clientPid, bool keep) {
+        int cameraId, int cameraFacing, int clientPid) {
     int callingPid = getCallingPid();
     LOG1("Client::Client E (pid %d, id %d)", callingPid, cameraId);
 
@@ -409,7 +346,6 @@
     mCameraId = cameraId;
     mCameraFacing = cameraFacing;
     mClientPid = clientPid;
-    mKeep = keep;
     mMsgEnabled = 0;
     mSurface = 0;
     mPreviewWindow = 0;
@@ -544,24 +480,18 @@
 }
 
 void CameraService::Client::disconnect() {
-    disconnectInternal(true);
-}
-
-void CameraService::Client::disconnectInternal(bool needCheckPid) {
     int callingPid = getCallingPid();
-    LOG1("disconnectInternal E (pid %d)", callingPid);
+    LOG1("disconnect E (pid %d)", callingPid);
     Mutex::Autolock lock(mLock);
 
-    if (needCheckPid) {
-        if (checkPid() != NO_ERROR) {
-            ALOGW("different client - don't disconnect");
-            return;
-        }
+    if (checkPid() != NO_ERROR) {
+        ALOGW("different client - don't disconnect");
+        return;
+    }
 
-        if (mClientPid <= 0) {
-            LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
-            return;
-        }
+    if (mClientPid <= 0) {
+        LOG1("camera is unlocked (mClientPid = %d), don't tear down hardware", mClientPid);
+        return;
     }
 
     // Make sure disconnect() is done once and once only, whether it is called
@@ -588,16 +518,8 @@
 
     mCameraService->removeClient(mCameraClient);
     mCameraService->setCameraFree(mCameraId);
-    mReleaseCondition.signal();
 
-    LOG1("disconnectInternal X (pid %d)", callingPid);
-}
-
-void CameraService::Client::waitRelease(int ms) {
-    Mutex::Autolock lock(mLock);
-    if (mHardware != 0) {
-        mReleaseCondition.waitRelative(mLock, ms * 1000000);
-    }
+    LOG1("disconnect X (pid %d)", callingPid);
 }
 
 // ----------------------------------------------------------------------------
@@ -1330,11 +1252,6 @@
     return -1;
 }
 
-// Whether the client wants to keep the camera from taking
-bool CameraService::Client::keep() const {
-    return mKeep;
-}
-
 // ----------------------------------------------------------------------------
 
 static const int kDumpLockRetries = 50;
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 7972201..5b63399 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -46,8 +46,7 @@
     virtual int32_t     getNumberOfCameras();
     virtual status_t    getCameraInfo(int cameraId,
                                       struct CameraInfo* cameraInfo);
-    virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId,
-                                bool force, bool keep);
+    virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId);
     virtual void        removeClient(const sp<ICameraClient>& cameraClient);
     // returns plain pointer of client. Note that mClientLock should be acquired to
     // prevent the client from destruction. The result can be NULL.
@@ -119,8 +118,7 @@
                                        const sp<CameraHardwareInterface>& hardware,
                                        int cameraId,
                                        int cameraFacing,
-                                       int clientPid,
-                                       bool keep);
+                                       int clientPid);
                                 ~Client();
 
         // return our camera client
@@ -179,19 +177,12 @@
                                     const sp<IBinder>& binder,
                                     const sp<ANativeWindow>& window);
 
-        void                    disconnectInternal(bool needCheckPid);
-        bool                    keep() const;
-        void                    waitRelease(int ms);
-
-
         // these are initialized in the constructor.
         sp<CameraService>               mCameraService;  // immutable after constructor
         sp<ICameraClient>               mCameraClient;
         int                             mCameraId;       // immutable after constructor
         int                             mCameraFacing;   // immutable after constructor
         pid_t                           mClientPid;
-        // Client wants to keep the camera from taking by other clients.
-        bool                            mKeep;
         sp<CameraHardwareInterface>     mHardware;       // cleared after disconnect()
         int                             mPreviewCallbackFlag;
         int                             mOrientation;     // Current display orientation
@@ -199,8 +190,6 @@
 
         // Ensures atomicity among the public methods
         mutable Mutex                   mLock;
-        // This will get notified when the hardware is released.
-        Condition                       mReleaseCondition;
         // This is a binder of Surface or SurfaceTexture.
         sp<IBinder>                     mSurface;
         sp<ANativeWindow>               mPreviewWindow;