Merge "Non-blocking audio I/O interface, WIP"
diff --git a/cmds/stagefright/SimplePlayer.cpp b/cmds/stagefright/SimplePlayer.cpp
index 0cfeb3e..7636906 100644
--- a/cmds/stagefright/SimplePlayer.cpp
+++ b/cmds/stagefright/SimplePlayer.cpp
@@ -22,6 +22,7 @@
 
 #include <gui/SurfaceTextureClient.h>
 #include <media/AudioTrack.h>
+#include <media/ICrypto.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -318,7 +319,9 @@
         CHECK(state->mCodec != NULL);
 
         err = state->mCodec->configure(
-                format, mNativeWindow->getSurfaceTextureClient(),
+                format,
+                mNativeWindow->getSurfaceTextureClient(),
+                NULL /* crypto */,
                 0 /* flags */);
 
         CHECK_EQ(err, (status_t)OK);
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index cf2909e..5cbfbfe 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -20,8 +20,10 @@
 
 #include "SimplePlayer.h"
 
+#include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
-
+#include <media/ICrypto.h>
+#include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -59,6 +61,33 @@
     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(
@@ -78,6 +107,8 @@
         return 1;
     }
 
+    sp<ICrypto> crypto;
+
     KeyedVector<size_t, CodecState> stateByTrack;
 
     bool haveAudio = false;
@@ -113,7 +144,38 @@
         state->mNumBuffersDecoded = 0;
         state->mIsAudio = isAudio;
 
-        if (decryptInputBuffers && !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 =
@@ -137,7 +199,8 @@
 
         err = state->mCodec->configure(
                 format, isVideo ? surface : NULL,
-                decryptInputBuffers ? MediaCodec::CONFIGURE_FLAG_SECURE : 0);
+                crypto,
+                0 /* flags */);
 
         CHECK_EQ(err, (status_t)OK);
 
diff --git a/include/media/AudioParameter.h b/include/media/AudioParameter.h
index 79d5d82..8cb2fa7 100644
--- a/include/media/AudioParameter.h
+++ b/include/media/AudioParameter.h
@@ -40,12 +40,12 @@
     //  keyFrameCount: to change audio output frame count, value is an int
     //  keyInputSource: to change audio input source, value is an int in audio_source_t
     //     (defined in media/mediarecorder.h)
-    static const char *keyRouting;
-    static const char *keySamplingRate;
-    static const char *keyFormat;
-    static const char *keyChannels;
-    static const char *keyFrameCount;
-    static const char *keyInputSource;
+    static const char * const keyRouting;
+    static const char * const keySamplingRate;
+    static const char * const keyFormat;
+    static const char * const keyChannels;
+    static const char * const keyFrameCount;
+    static const char * const keyInputSource;
 
     String8 toString();
 
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index e64bc3f..471f462 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -88,6 +88,19 @@
     static status_t getOutputSamplingRate(int* samplingRate, audio_stream_type_t stream = AUDIO_STREAM_DEFAULT);
     static status_t getOutputFrameCount(int* frameCount, audio_stream_type_t stream = AUDIO_STREAM_DEFAULT);
     static status_t getOutputLatency(uint32_t* latency, audio_stream_type_t stream = AUDIO_STREAM_DEFAULT);
+    static status_t getSamplingRate(audio_io_handle_t output,
+                                          audio_stream_type_t streamType,
+                                          int* samplingRate);
+    // returns the number of frames per audio HAL write buffer. Corresponds to
+    // audio_stream->get_buffer_size()/audio_stream_frame_size()
+    static status_t getFrameCount(audio_io_handle_t output,
+                                  audio_stream_type_t stream,
+                                  int* frameCount);
+    // returns the audio output stream latency in ms. Corresponds to
+    // audio_stream_out->get_latency()
+    static status_t getLatency(audio_io_handle_t output,
+                               audio_stream_type_t stream,
+                               uint32_t* latency);
 
     // DEPRECATED
     static status_t getOutputSamplingRate(int* samplingRate, int stream = AUDIO_STREAM_DEFAULT);
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 7d5d772..6de6486 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -139,13 +139,15 @@
      *                     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:              Reserved for future use.
+     * flags:              See comments on audio_policy_output_flags_t in <system/audio_policy.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.
      * notificationFrames: The callback function is called each time notificationFrames PCM
      *                     frames have been consumed from track input buffer.
      * sessionId:          Specific session ID, or zero to use default.
+     * threadCanCallJava:  Whether callbacks are made from an attached thread and thus can call JNI.
+     *                     If not present in parameter list, then fixed at false.
      */
 
                         AudioTrack( audio_stream_type_t streamType,
@@ -157,7 +159,7 @@
                                     callback_t cbf       = NULL,
                                     void* user           = NULL,
                                     int notificationFrames = 0,
-                                    int sessionId = 0);
+                                    int sessionId        = 0);
 
                         // DEPRECATED
                         explicit AudioTrack( int streamType,
@@ -189,7 +191,7 @@
                                     callback_t cbf      = NULL,
                                     void* user          = NULL,
                                     int notificationFrames = 0,
-                                    int sessionId = 0);
+                                    int sessionId       = 0);
 
     /* Terminates the AudioTrack and unregisters it from AudioFlinger.
      * Also destroys all resources associated with the AudioTrack.
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 8239b0e..9e938d1 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -29,6 +29,7 @@
 #include <media/IAudioFlingerClient.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
 #include <hardware/audio_effect.h>
 #include <media/IEffect.h>
 #include <media/IEffectClient.h>
@@ -126,23 +127,24 @@
     // retrieve the audio recording buffer size
     virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const = 0;
 
-    virtual audio_io_handle_t openOutput(uint32_t *pDevices,
-                                    uint32_t *pSamplingRate,
-                                    audio_format_t *pFormat,
-                                    uint32_t *pChannels,
-                                    uint32_t *pLatencyMs,
-                                    audio_policy_output_flags_t flags) = 0;
+    virtual audio_io_handle_t openOutput(audio_module_handle_t module,
+                                         audio_devices_t *pDevices,
+                                         uint32_t *pSamplingRate,
+                                         audio_format_t *pFormat,
+                                         audio_channel_mask_t *pChannelMask,
+                                         uint32_t *pLatencyMs,
+                                         audio_policy_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;
     virtual status_t suspendOutput(audio_io_handle_t output) = 0;
     virtual status_t restoreOutput(audio_io_handle_t output) = 0;
 
-    virtual audio_io_handle_t openInput(uint32_t *pDevices,
-                                    uint32_t *pSamplingRate,
-                                    audio_format_t *pFormat,
-                                    uint32_t *pChannels,
-                                    audio_in_acoustics_t acoustics) = 0;
+    virtual audio_io_handle_t openInput(audio_module_handle_t module,
+                                        audio_devices_t *pDevices,
+                                        uint32_t *pSamplingRate,
+                                        audio_format_t *pFormat,
+                                        audio_channel_mask_t *pChannelMask) = 0;
     virtual status_t closeInput(audio_io_handle_t input) = 0;
 
     virtual status_t setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output) = 0;
@@ -178,6 +180,8 @@
 
     virtual status_t moveEffects(int session, audio_io_handle_t srcOutput,
                                     audio_io_handle_t dstOutput) = 0;
+
+    virtual audio_module_handle_t loadHwModule(const char *name) = 0;
 };
 
 
diff --git a/include/media/ICrypto.h b/include/media/ICrypto.h
index 916abe0..376c326 100644
--- a/include/media/ICrypto.h
+++ b/include/media/ICrypto.h
@@ -16,6 +16,7 @@
 
 #include <binder/IInterface.h>
 #include <media/stagefright/foundation/ABase.h>
+#include <media/hardware/CryptoAPI.h>
 
 #ifndef ANDROID_ICRYPTO_H_
 
@@ -26,26 +27,26 @@
 struct ICrypto : public IInterface {
     DECLARE_META_INTERFACE(Crypto);
 
-    virtual status_t initialize() = 0;
-    virtual status_t terminate() = 0;
+    virtual status_t initCheck() const = 0;
 
-    virtual status_t setEntitlementKey(
-            const void *key, size_t keyLength) = 0;
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const = 0;
 
-    virtual status_t setEntitlementControlMessage(
-            const void *msg, size_t msgLength) = 0;
+    virtual status_t createPlugin(
+            const uint8_t uuid[16], const void *data, size_t size) = 0;
 
-    // "dstData" is in media_server's address space (but inaccessible).
-    virtual ssize_t decryptVideo(
-            const void *iv, size_t ivLength,
-            const void *srcData, size_t srcDataSize,
-            void *dstData, size_t dstDataOffset) = 0;
+    virtual status_t destroyPlugin() = 0;
 
-    // "dstData" is in the calling process' address space.
-    virtual ssize_t decryptAudio(
-            const void *iv, size_t ivLength,
-            const void *srcData, size_t srcDataSize,
-            void *dstData, size_t dstDataSize) = 0;
+    virtual bool requiresSecureDecoderComponent(
+            const char *mime) const = 0;
+
+    virtual status_t decrypt(
+            bool secure,
+            const uint8_t key[16],
+            const uint8_t iv[16],
+            CryptoPlugin::Mode mode,
+            const void *srcPtr,
+            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
+            void *dstPtr) = 0;
 
 private:
     DISALLOW_EVIL_CONSTRUCTORS(ICrypto);
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index d4aa233..9a8f4b0 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -87,8 +87,9 @@
         virtual ssize_t     frameSize() const = 0;
         virtual uint32_t    latency() const = 0;
         virtual float       msecsPerFrame() const = 0;
-        virtual status_t    getPosition(uint32_t *position) = 0;
-        virtual int         getSessionId() = 0;
+        virtual status_t    getPosition(uint32_t *position) const = 0;
+        virtual status_t    getFramesWritten(uint32_t *frameswritten) const = 0;
+        virtual int         getSessionId() const = 0;
 
         // If no callback is specified, use the "write" API below to submit
         // audio data.
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 0fc88e1..0b0d511 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -34,7 +34,6 @@
 struct MediaCodec : public AHandler {
     enum ConfigureFlags {
         CONFIGURE_FLAG_ENCODE   = 1,
-        CONFIGURE_FLAG_SECURE   = 2,
     };
 
     enum BufferFlags {
@@ -53,6 +52,7 @@
     status_t configure(
             const sp<AMessage> &format,
             const sp<SurfaceTextureClient> &nativeWindow,
+            const sp<ICrypto> &crypto,
             uint32_t flags);
 
     status_t start();
diff --git a/include/media/stagefright/MediaCodecList.h b/include/media/stagefright/MediaCodecList.h
index 14dc1b8..dfb845b 100644
--- a/include/media/stagefright/MediaCodecList.h
+++ b/include/media/stagefright/MediaCodecList.h
@@ -36,9 +36,22 @@
 
     ssize_t findCodecByName(const char *name) const;
 
+    size_t countCodecs() const;
     const char *getCodecName(size_t index) const;
+    bool isEncoder(size_t index) const;
     bool codecHasQuirk(size_t index, const char *quirkName) const;
 
+    status_t getSupportedTypes(size_t index, Vector<AString> *types) const;
+
+    struct ProfileLevel {
+        uint32_t mProfile;
+        uint32_t mLevel;
+    };
+    status_t getCodecCapabilities(
+            size_t index, const char *type,
+            Vector<ProfileLevel> *profileLevels,
+            Vector<uint32_t> *colorFormats) const;
+
 private:
     enum Section {
         SECTION_TOPLEVEL,
diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h
index dd3bf28..8889520 100644
--- a/include/media/stagefright/MediaErrors.h
+++ b/include/media/stagefright/MediaErrors.h
@@ -55,16 +55,12 @@
     ERROR_DRM_CANNOT_HANDLE                 = DRM_ERROR_BASE - 6,
     ERROR_DRM_TAMPER_DETECTED               = DRM_ERROR_BASE - 7,
 
+    ERROR_DRM_WV_VENDOR_MAX                 = DRM_ERROR_BASE - 500,
+    ERROR_DRM_WV_VENDOR_MIN                 = DRM_ERROR_BASE - 999,
+
     // Heartbeat Error Codes
     HEARTBEAT_ERROR_BASE = -3000,
-
-    ERROR_HEARTBEAT_AUTHENTICATION_FAILURE                  = HEARTBEAT_ERROR_BASE,
-    ERROR_HEARTBEAT_NO_ACTIVE_PURCHASE_AGREEMENT            = HEARTBEAT_ERROR_BASE - 1,
-    ERROR_HEARTBEAT_CONCURRENT_PLAYBACK                     = HEARTBEAT_ERROR_BASE - 2,
-    ERROR_HEARTBEAT_UNUSUAL_ACTIVITY                        = HEARTBEAT_ERROR_BASE - 3,
-    ERROR_HEARTBEAT_STREAMING_UNAVAILABLE                   = HEARTBEAT_ERROR_BASE - 4,
-    ERROR_HEARTBEAT_CANNOT_ACTIVATE_RENTAL                  = HEARTBEAT_ERROR_BASE - 5,
-    ERROR_HEARTBEAT_TERMINATE_REQUESTED                     = HEARTBEAT_ERROR_BASE - 6,
+    ERROR_HEARTBEAT_TERMINATE_REQUESTED                     = HEARTBEAT_ERROR_BASE,
 };
 
 }  // namespace android
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 7d51dee..bf054ac 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -384,6 +384,11 @@
         const char *mimeType, bool queryDecoders,
         Vector<CodecCapabilities> *results);
 
+status_t QueryCodec(
+        const sp<IOMX> &omx,
+        const char *componentName, const char *mime,
+        bool isEncoder,
+        CodecCapabilities *caps);
 
 }  // namespace android
 
diff --git a/libvideoeditor/lvpp/VideoEditorPlayer.cpp b/libvideoeditor/lvpp/VideoEditorPlayer.cpp
index 57cab08..1ba1f44 100755
--- a/libvideoeditor/lvpp/VideoEditorPlayer.cpp
+++ b/libvideoeditor/lvpp/VideoEditorPlayer.cpp
@@ -376,12 +376,19 @@
     return mMsecsPerFrame;
 }
 
-status_t VideoEditorPlayer::VeAudioOutput::getPosition(uint32_t *position) {
+status_t VideoEditorPlayer::VeAudioOutput::getPosition(uint32_t *position) const {
 
     if (mTrack == 0) return NO_INIT;
     return mTrack->getPosition(position);
 }
 
+status_t VideoEditorPlayer::VeAudioOutput::getFramesWritten(uint32_t *written) const {
+
+    if (mTrack == 0) return NO_INIT;
+    *written = mNumFramesWritten;
+    return OK;
+}
+
 status_t VideoEditorPlayer::VeAudioOutput::open(
         uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
         audio_format_t format, int bufferCount,
@@ -569,7 +576,7 @@
     return NO_ERROR;
 }
 
-int VideoEditorPlayer::VeAudioOutput::getSessionId() {
+int VideoEditorPlayer::VeAudioOutput::getSessionId() const {
 
     return mSessionId;
 }
diff --git a/libvideoeditor/lvpp/VideoEditorPlayer.h b/libvideoeditor/lvpp/VideoEditorPlayer.h
index 6962501..350b384 100755
--- a/libvideoeditor/lvpp/VideoEditorPlayer.h
+++ b/libvideoeditor/lvpp/VideoEditorPlayer.h
@@ -45,8 +45,9 @@
         virtual ssize_t         frameSize() const;
         virtual uint32_t        latency() const;
         virtual float           msecsPerFrame() const;
-        virtual status_t        getPosition(uint32_t *position);
-        virtual int             getSessionId();
+        virtual status_t        getPosition(uint32_t *position) const;
+        virtual status_t        getFramesWritten(uint32_t*) const;
+        virtual int             getSessionId() const;
 
         virtual status_t        open(
                 uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
index abc7b3f..9766ee6 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -19,16 +19,18 @@
 
 #include <utils/Log.h>
 
+#include <hardware/audio.h>
 #include <media/AudioParameter.h>
 
 namespace android {
 
-const char *AudioParameter::keyRouting = "routing";
-const char *AudioParameter::keySamplingRate = "sampling_rate";
-const char *AudioParameter::keyFormat = "format";
-const char *AudioParameter::keyChannels = "channels";
-const char *AudioParameter::keyFrameCount = "frame_count";
-const char *AudioParameter::keyInputSource = "input_source";
+// static
+const char * const AudioParameter::keyRouting = AUDIO_PARAMETER_STREAM_ROUTING;
+const char * const AudioParameter::keySamplingRate = AUDIO_PARAMETER_STREAM_SAMPLING_RATE;
+const char * const AudioParameter::keyFormat = AUDIO_PARAMETER_STREAM_FORMAT;
+const char * const AudioParameter::keyChannels = AUDIO_PARAMETER_STREAM_CHANNELS;
+const char * const AudioParameter::keyFrameCount = AUDIO_PARAMETER_STREAM_FRAME_COUNT;
+const char * const AudioParameter::keyInputSource = AUDIO_PARAMETER_STREAM_INPUT_SOURCE;
 
 AudioParameter::AudioParameter(const String8& keyValuePairs)
 {
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 33c7d03..2596f07 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -36,7 +36,6 @@
 audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
 // Cached values
 
-DefaultKeyedVector<audio_stream_type_t, audio_io_handle_t> AudioSystem::gStreamOutputMap(0);
 DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(0);
 
 // Cached values for recording queries, all protected by gLock
@@ -213,7 +212,6 @@
 
 status_t AudioSystem::getOutputSamplingRate(int* samplingRate, audio_stream_type_t streamType)
 {
-    OutputDescriptor *outputDesc;
     audio_io_handle_t output;
 
     if (streamType == AUDIO_STREAM_DEFAULT) {
@@ -225,6 +223,15 @@
         return PERMISSION_DENIED;
     }
 
+    return getSamplingRate(output, streamType, samplingRate);
+}
+
+status_t AudioSystem::getSamplingRate(audio_io_handle_t output,
+                                      audio_stream_type_t streamType,
+                                      int* samplingRate)
+{
+    OutputDescriptor *outputDesc;
+
     gLock.lock();
     outputDesc = AudioSystem::gOutputs.valueFor(output);
     if (outputDesc == NULL) {
@@ -239,7 +246,7 @@
         gLock.unlock();
     }
 
-    ALOGV("getOutputSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, *samplingRate);
+    ALOGV("getSamplingRate() streamType %d, output %d, sampling rate %d", streamType, output, *samplingRate);
 
     return NO_ERROR;
 }
@@ -251,7 +258,6 @@
 
 status_t AudioSystem::getOutputFrameCount(int* frameCount, audio_stream_type_t streamType)
 {
-    OutputDescriptor *outputDesc;
     audio_io_handle_t output;
 
     if (streamType == AUDIO_STREAM_DEFAULT) {
@@ -263,6 +269,15 @@
         return PERMISSION_DENIED;
     }
 
+    return getFrameCount(output, streamType, frameCount);
+}
+
+status_t AudioSystem::getFrameCount(audio_io_handle_t output,
+                                    audio_stream_type_t streamType,
+                                    int* frameCount)
+{
+    OutputDescriptor *outputDesc;
+
     gLock.lock();
     outputDesc = AudioSystem::gOutputs.valueFor(output);
     if (outputDesc == NULL) {
@@ -275,14 +290,13 @@
         gLock.unlock();
     }
 
-    ALOGV("getOutputFrameCount() streamType %d, output %d, frameCount %d", streamType, output, *frameCount);
+    ALOGV("getFrameCount() streamType %d, output %d, frameCount %d", streamType, output, *frameCount);
 
     return NO_ERROR;
 }
 
 status_t AudioSystem::getOutputLatency(uint32_t* latency, audio_stream_type_t streamType)
 {
-    OutputDescriptor *outputDesc;
     audio_io_handle_t output;
 
     if (streamType == AUDIO_STREAM_DEFAULT) {
@@ -294,6 +308,15 @@
         return PERMISSION_DENIED;
     }
 
+    return getLatency(output, streamType, latency);
+}
+
+status_t AudioSystem::getLatency(audio_io_handle_t output,
+                                 audio_stream_type_t streamType,
+                                 uint32_t* latency)
+{
+    OutputDescriptor *outputDesc;
+
     gLock.lock();
     outputDesc = AudioSystem::gOutputs.valueFor(output);
     if (outputDesc == NULL) {
@@ -306,7 +329,7 @@
         gLock.unlock();
     }
 
-    ALOGV("getOutputLatency() streamType %d, output %d, latency %d", streamType, output, *latency);
+    ALOGV("getLatency() streamType %d, output %d, latency %d", streamType, output, *latency);
 
     return NO_ERROR;
 }
@@ -395,7 +418,6 @@
 
     AudioSystem::gAudioFlinger.clear();
     // clear output handles and stream to output map caches
-    AudioSystem::gStreamOutputMap.clear();
     AudioSystem::gOutputs.clear();
 
     if (gAudioErrorCallback) {
@@ -416,12 +438,6 @@
 
     switch (event) {
     case STREAM_CONFIG_CHANGED:
-        if (param2 == NULL) break;
-        stream = *(const audio_stream_type_t *)param2;
-        ALOGV("ioConfigChanged() STREAM_CONFIG_CHANGED stream %d, output %d", stream, ioHandle);
-        if (gStreamOutputMap.indexOfKey(stream) >= 0) {
-            gStreamOutputMap.replaceValueFor(stream, ioHandle);
-        }
         break;
     case OUTPUT_OPENED: {
         if (gOutputs.indexOfKey(ioHandle) >= 0) {
@@ -444,11 +460,6 @@
         ALOGV("ioConfigChanged() output %d closed", ioHandle);
 
         gOutputs.removeItem(ioHandle);
-        for (int i = gStreamOutputMap.size() - 1; i >= 0 ; i--) {
-            if (gStreamOutputMap.valueAt(i) == ioHandle) {
-                gStreamOutputMap.removeItemsAt(i);
-            }
-        }
         } break;
 
     case OUTPUT_CONFIG_CHANGED: {
@@ -580,33 +591,9 @@
                                     uint32_t channels,
                                     audio_policy_output_flags_t flags)
 {
-    audio_io_handle_t output = 0;
-    // Do not use stream to output map cache if the direct output
-    // flag is set or if we are likely to use a direct output
-    // (e.g voice call stream @ 8kHz could use BT SCO device and be routed to
-    // a direct output on some platforms).
-    // TODO: the output cache and stream to output mapping implementation needs to
-    // be reworked for proper operation with direct outputs. This code is too specific
-    // to the first use case we want to cover (Voice Recognition and Voice Dialer over
-    // Bluetooth SCO
-    if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) == 0 &&
-        ((stream != AUDIO_STREAM_VOICE_CALL && stream != AUDIO_STREAM_BLUETOOTH_SCO) ||
-         channels != AUDIO_CHANNEL_OUT_MONO ||
-         (samplingRate != 8000 && samplingRate != 16000))) {
-        Mutex::Autolock _l(gLock);
-        output = AudioSystem::gStreamOutputMap.valueFor(stream);
-        ALOGV_IF((output != 0), "getOutput() read %d from cache for stream %d", output, stream);
-    }
-    if (output == 0) {
-        const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
-        if (aps == 0) return 0;
-        output = aps->getOutput(stream, samplingRate, format, channels, flags);
-        if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) == 0) {
-            Mutex::Autolock _l(gLock);
-            AudioSystem::gStreamOutputMap.add(stream, output);
-        }
-    }
-    return output;
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return 0;
+    return aps->getOutput(stream, samplingRate, format, channels, flags);
 }
 
 status_t AudioSystem::startOutput(audio_io_handle_t output,
@@ -754,7 +741,6 @@
 {
     Mutex::Autolock _l(gLock);
     ALOGV("clearAudioConfigCache()");
-    gStreamOutputMap.clear();
     gOutputs.clear();
 }
 
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index d73eabd..6dc6c41 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -185,27 +185,23 @@
 
     ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
 
+    ALOGV("set() streamType %d frameCount %d flags %04x", streamType, frameCount, flags);
+
     AutoMutex lock(mLock);
     if (mAudioTrack != 0) {
         ALOGE("Track already in use");
         return INVALID_OPERATION;
     }
 
-    int afSampleRate;
-    if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
-        return NO_INIT;
-    }
-
-    uint32_t afLatency;
-    if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
-        return NO_INIT;
-    }
-
     // handle default values first.
     if (streamType == AUDIO_STREAM_DEFAULT) {
         streamType = AUDIO_STREAM_MUSIC;
     }
 
+    int afSampleRate;
+    if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
+        return NO_INIT;
+    }
     if (sampleRate == 0) {
         sampleRate = afSampleRate;
     }
@@ -226,7 +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);
+        flags = (audio_policy_output_flags_t)
+                ((flags | AUDIO_POLICY_OUTPUT_FLAG_DIRECT) & ~AUDIO_POLICY_OUTPUT_FLAG_FAST);
     }
 
     if (!audio_is_output_channel(channelMask)) {
@@ -252,6 +249,7 @@
     mNotificationFramesReq = notificationFrames;
     mSessionId = sessionId;
     mAuxEffectId = 0;
+    mCbf = cbf;
 
     // create the IAudioTrack
     status_t status = createTrack_l(streamType,
@@ -280,7 +278,6 @@
     mSharedBuffer = sharedBuffer;
     mMuted = false;
     mActive = false;
-    mCbf = cbf;
     mUserData = user;
     mLoopCount = 0;
     mMarkerPosition = 0;
@@ -750,18 +747,31 @@
     }
 
     int afSampleRate;
-    if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
+    if (AudioSystem::getSamplingRate(output, streamType, &afSampleRate) != NO_ERROR) {
         return NO_INIT;
     }
     int afFrameCount;
-    if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
+    if (AudioSystem::getFrameCount(output, streamType, &afFrameCount) != NO_ERROR) {
         return NO_INIT;
     }
     uint32_t afLatency;
-    if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
+    if (AudioSystem::getLatency(output, streamType, &afLatency) != NO_ERROR) {
         return NO_INIT;
     }
 
+    // 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) && !(
+            // 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);
+    }
+    ALOGV("createTrack_l() output %d afFrameCount %d afLatency %d", output, afFrameCount, afLatency);
+
     mNotificationFramesAct = mNotificationFramesReq;
     if (!audio_is_linear_pcm(format)) {
         if (sharedBuffer != 0) {
@@ -786,7 +796,7 @@
             if (mNotificationFramesAct > (uint32_t)frameCount/2) {
                 mNotificationFramesAct = frameCount/2;
             }
-            if (frameCount < minFrameCount) {
+            if (frameCount < minFrameCount && !(flags & AUDIO_POLICY_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);
@@ -807,6 +817,10 @@
     if (mIsTimed) {
         trackFlags |= IAudioFlinger::TRACK_TIMED;
     }
+    if (flags & AUDIO_POLICY_OUTPUT_FLAG_FAST) {
+        trackFlags |= IAudioFlinger::TRACK_FAST;
+    }
+
     sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
                                                       streamType,
                                                       sampleRate,
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index ce10c8e..81e259a 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -69,7 +69,8 @@
     QUERY_EFFECT,
     GET_EFFECT_DESCRIPTOR,
     CREATE_EFFECT,
-    MOVE_EFFECTS
+    MOVE_EFFECTS,
+    LOAD_HW_MODULE
 };
 
 class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -355,38 +356,40 @@
         return reply.readInt32();
     }
 
-    virtual audio_io_handle_t openOutput(uint32_t *pDevices,
-                            uint32_t *pSamplingRate,
-                            audio_format_t *pFormat,
-                            uint32_t *pChannels,
-                            uint32_t *pLatencyMs,
-                            audio_policy_output_flags_t flags)
+    virtual audio_io_handle_t openOutput(audio_module_handle_t module,
+                                         audio_devices_t *pDevices,
+                                         uint32_t *pSamplingRate,
+                                         audio_format_t *pFormat,
+                                         audio_channel_mask_t *pChannelMask,
+                                         uint32_t *pLatencyMs,
+                                         audio_policy_output_flags_t flags)
     {
         Parcel data, reply;
-        uint32_t devices = pDevices ? *pDevices : 0;
+        audio_devices_t devices = pDevices ? *pDevices : (audio_devices_t)0;
         uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
         audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT;
-        uint32_t channels = pChannels ? *pChannels : 0;
+        audio_channel_mask_t channelMask = pChannelMask ? *pChannelMask : (audio_channel_mask_t)0;
         uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
 
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(module);
         data.writeInt32(devices);
         data.writeInt32(samplingRate);
         data.writeInt32(format);
-        data.writeInt32(channels);
+        data.writeInt32(channelMask);
         data.writeInt32(latency);
         data.writeInt32((int32_t) flags);
         remote()->transact(OPEN_OUTPUT, data, &reply);
         audio_io_handle_t output = (audio_io_handle_t) reply.readInt32();
         ALOGV("openOutput() returned output, %d", output);
-        devices = reply.readInt32();
+        devices = (audio_devices_t)reply.readInt32();
         if (pDevices) *pDevices = devices;
         samplingRate = reply.readInt32();
         if (pSamplingRate) *pSamplingRate = samplingRate;
         format = (audio_format_t) reply.readInt32();
         if (pFormat) *pFormat = format;
-        channels = reply.readInt32();
-        if (pChannels) *pChannels = channels;
+        channelMask = (audio_channel_mask_t)reply.readInt32();
+        if (pChannelMask) *pChannelMask = channelMask;
         latency = reply.readInt32();
         if (pLatencyMs) *pLatencyMs = latency;
         return output;
@@ -430,34 +433,34 @@
         return reply.readInt32();
     }
 
-    virtual audio_io_handle_t openInput(uint32_t *pDevices,
-                            uint32_t *pSamplingRate,
-                            audio_format_t *pFormat,
-                            uint32_t *pChannels,
-                            audio_in_acoustics_t acoustics)
+    virtual audio_io_handle_t openInput(audio_module_handle_t module,
+                                        audio_devices_t *pDevices,
+                                        uint32_t *pSamplingRate,
+                                        audio_format_t *pFormat,
+                                        audio_channel_mask_t *pChannelMask)
     {
         Parcel data, reply;
-        uint32_t devices = pDevices ? *pDevices : 0;
+        audio_devices_t devices = pDevices ? *pDevices : (audio_devices_t)0;
         uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
         audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT;
-        uint32_t channels = pChannels ? *pChannels : 0;
+        audio_channel_mask_t channelMask = pChannelMask ? *pChannelMask : (audio_channel_mask_t)0;
 
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(module);
         data.writeInt32(devices);
         data.writeInt32(samplingRate);
         data.writeInt32(format);
-        data.writeInt32(channels);
-        data.writeInt32((int32_t) acoustics);
+        data.writeInt32(channelMask);
         remote()->transact(OPEN_INPUT, data, &reply);
         audio_io_handle_t input = (audio_io_handle_t) reply.readInt32();
-        devices = reply.readInt32();
+        devices = (audio_devices_t)reply.readInt32();
         if (pDevices) *pDevices = devices;
         samplingRate = reply.readInt32();
         if (pSamplingRate) *pSamplingRate = samplingRate;
         format = (audio_format_t) reply.readInt32();
         if (pFormat) *pFormat = format;
-        channels = reply.readInt32();
-        if (pChannels) *pChannels = channels;
+        channelMask = (audio_channel_mask_t)reply.readInt32();
+        if (pChannelMask) *pChannelMask = channelMask;
         return input;
     }
 
@@ -668,6 +671,15 @@
         remote()->transact(MOVE_EFFECTS, data, &reply);
         return reply.readInt32();
     }
+
+    virtual audio_module_handle_t loadHwModule(const char *name)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeCString(name);
+        remote()->transact(LOAD_HW_MODULE, data, &reply);
+        return (audio_module_handle_t) reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -837,24 +849,26 @@
         } break;
         case OPEN_OUTPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            uint32_t devices = data.readInt32();
+            audio_module_handle_t module = (audio_module_handle_t)data.readInt32();
+            audio_devices_t devices = (audio_devices_t)data.readInt32();
             uint32_t samplingRate = data.readInt32();
             audio_format_t format = (audio_format_t) data.readInt32();
-            uint32_t channels = 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_io_handle_t output = openOutput(&devices,
-                                     &samplingRate,
-                                     &format,
-                                     &channels,
-                                     &latency,
-                                     flags);
+            audio_io_handle_t output = openOutput(module,
+                                                 &devices,
+                                                 &samplingRate,
+                                                 &format,
+                                                 &channelMask,
+                                                 &latency,
+                                                 flags);
             ALOGV("OPEN_OUTPUT output, %p", output);
             reply->writeInt32((int32_t) output);
             reply->writeInt32(devices);
             reply->writeInt32(samplingRate);
             reply->writeInt32(format);
-            reply->writeInt32(channels);
+            reply->writeInt32(channelMask);
             reply->writeInt32(latency);
             return NO_ERROR;
         } break;
@@ -882,22 +896,22 @@
         } break;
         case OPEN_INPUT: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            uint32_t devices = data.readInt32();
+            audio_module_handle_t module = (audio_module_handle_t)data.readInt32();
+            audio_devices_t devices = (audio_devices_t)data.readInt32();
             uint32_t samplingRate = data.readInt32();
             audio_format_t format = (audio_format_t) data.readInt32();
-            uint32_t channels = data.readInt32();
-            audio_in_acoustics_t acoustics = (audio_in_acoustics_t) data.readInt32();
+            audio_channel_mask_t channelMask = (audio_channel_mask_t)data.readInt32();
 
-            audio_io_handle_t input = openInput(&devices,
-                                     &samplingRate,
-                                     &format,
-                                     &channels,
-                                     acoustics);
+            audio_io_handle_t input = openInput(module,
+                                             &devices,
+                                             &samplingRate,
+                                             &format,
+                                             &channelMask);
             reply->writeInt32((int32_t) input);
             reply->writeInt32(devices);
             reply->writeInt32(samplingRate);
             reply->writeInt32(format);
-            reply->writeInt32(channels);
+            reply->writeInt32(channelMask);
             return NO_ERROR;
         } break;
         case CLOSE_INPUT: {
@@ -1015,6 +1029,11 @@
             reply->writeInt32(moveEffects(session, srcOutput, dstOutput));
             return NO_ERROR;
         } break;
+        case LOAD_HW_MODULE: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            reply->writeInt32(loadHwModule(data.readCString()));
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index 827d7af..1fe6bed 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -25,12 +25,12 @@
 namespace android {
 
 enum {
-    INITIALIZE = IBinder::FIRST_CALL_TRANSACTION,
-    TERMINATE,
-    SET_ENTITLEMENT_KEY,
-    SET_ECM,
-    DECRYPT_VIDEO,
-    DECRYPT_AUDIO,
+    INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION,
+    IS_CRYPTO_SUPPORTED,
+    CREATE_PLUGIN,
+    DESTROY_PLUGIN,
+    REQUIRES_SECURE_COMPONENT,
+    DECRYPT,
 };
 
 struct BpCrypto : public BpInterface<ICrypto> {
@@ -38,104 +38,97 @@
         : BpInterface<ICrypto>(impl) {
     }
 
-    virtual status_t initialize() {
+    virtual status_t initCheck() const {
         Parcel data, reply;
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        remote()->transact(INITIALIZE, data, &reply);
+        remote()->transact(INIT_CHECK, data, &reply);
 
         return reply.readInt32();
     }
 
-    virtual status_t terminate() {
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const {
         Parcel data, reply;
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        remote()->transact(TERMINATE, data, &reply);
+        data.write(uuid, 16);
+        remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply);
+
+        return reply.readInt32() != 0;
+    }
+
+    virtual status_t createPlugin(
+            const uint8_t uuid[16], const void *opaqueData, size_t opaqueSize) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+        data.write(uuid, 16);
+        data.writeInt32(opaqueSize);
+        data.write(opaqueData, opaqueSize);
+        remote()->transact(CREATE_PLUGIN, data, &reply);
 
         return reply.readInt32();
     }
 
-    virtual status_t setEntitlementKey(
-            const void *key, size_t keyLength) {
+    virtual status_t destroyPlugin() {
         Parcel data, reply;
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        data.writeInt32(keyLength);
-        data.write(key, keyLength);
-        remote()->transact(SET_ENTITLEMENT_KEY, data, &reply);
+        remote()->transact(DESTROY_PLUGIN, data, &reply);
 
         return reply.readInt32();
     }
 
-    virtual status_t setEntitlementControlMessage(
-            const void *msg, size_t msgLength) {
+    virtual bool requiresSecureDecoderComponent(
+            const char *mime) const {
         Parcel data, reply;
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        data.writeInt32(msgLength);
-        data.write(msg, msgLength);
-        remote()->transact(SET_ECM, data, &reply);
+        data.writeCString(mime);
+        remote()->transact(REQUIRES_SECURE_COMPONENT, data, &reply);
 
-        return reply.readInt32();
+        return reply.readInt32() != 0;
     }
 
-    virtual ssize_t decryptVideo(
-            const void *iv, size_t ivLength,
-            const void *srcData, size_t srcDataSize,
-            void *dstData, size_t dstDataOffset) {
+    virtual status_t decrypt(
+            bool secure,
+            const uint8_t key[16],
+            const uint8_t iv[16],
+            CryptoPlugin::Mode mode,
+            const void *srcPtr,
+            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
+            void *dstPtr) {
         Parcel data, reply;
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        if (iv == NULL) {
-            if (ivLength > 0) {
-                return -EINVAL;
-            }
+        data.writeInt32(secure);
+        data.writeInt32(mode);
+        data.write(key, 16);
+        data.write(iv, 16);
 
-            data.writeInt32(-1);
-        } else {
-            data.writeInt32(ivLength);
-            data.write(iv, ivLength);
+        size_t totalSize = 0;
+        for (size_t i = 0; i < numSubSamples; ++i) {
+            totalSize += subSamples[i].mNumBytesOfEncryptedData;
+            totalSize += subSamples[i].mNumBytesOfClearData;
         }
 
-        data.writeInt32(srcDataSize);
-        data.write(srcData, srcDataSize);
+        data.writeInt32(totalSize);
+        data.write(srcPtr, totalSize);
 
-        data.writeIntPtr((intptr_t)dstData);
-        data.writeInt32(dstDataOffset);
+        data.writeInt32(numSubSamples);
+        data.write(subSamples, sizeof(CryptoPlugin::SubSample) * numSubSamples);
 
-        remote()->transact(DECRYPT_VIDEO, data, &reply);
-
-        return reply.readInt32();
-    }
-
-    virtual ssize_t decryptAudio(
-            const void *iv, size_t ivLength,
-            const void *srcData, size_t srcDataSize,
-            void *dstData, size_t dstDataSize) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        if (iv == NULL) {
-            if (ivLength > 0) {
-                return -EINVAL;
-            }
-
-            data.writeInt32(-1);
-        } else {
-            data.writeInt32(ivLength);
-            data.write(iv, ivLength);
+        if (secure) {
+            data.writeIntPtr((intptr_t)dstPtr);
         }
 
-        data.writeInt32(srcDataSize);
-        data.write(srcData, srcDataSize);
-        data.writeInt32(dstDataSize);
+        remote()->transact(DECRYPT, data, &reply);
 
-        remote()->transact(DECRYPT_AUDIO, data, &reply);
+        status_t result = reply.readInt32();
 
-        ssize_t res = reply.readInt32();
-
-        if (res <= 0) {
-            return res;
+        if (result != OK) {
+            return result;
         }
 
-        reply.read(dstData, res);
+        if (!secure) {
+            reply.read(dstPtr, totalSize);
+        }
 
-        return res;
+        return OK;
     }
 
 private:
@@ -149,138 +142,120 @@
 status_t BnCrypto::onTransact(
     uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
     switch (code) {
-        case INITIALIZE:
+        case INIT_CHECK:
         {
             CHECK_INTERFACE(ICrypto, data, reply);
-            reply->writeInt32(initialize());
+            reply->writeInt32(initCheck());
 
             return OK;
         }
 
-        case TERMINATE:
+        case IS_CRYPTO_SUPPORTED:
         {
             CHECK_INTERFACE(ICrypto, data, reply);
-            reply->writeInt32(terminate());
+            uint8_t uuid[16];
+            data.read(uuid, sizeof(uuid));
+            reply->writeInt32(isCryptoSchemeSupported(uuid));
 
             return OK;
         }
 
-        case SET_ENTITLEMENT_KEY:
+        case CREATE_PLUGIN:
         {
             CHECK_INTERFACE(ICrypto, data, reply);
 
-            size_t keyLength = data.readInt32();
-            void *key = malloc(keyLength);
-            data.read(key, keyLength);
+            uint8_t uuid[16];
+            data.read(uuid, sizeof(uuid));
 
-            reply->writeInt32(setEntitlementKey(key, keyLength));
+            size_t opaqueSize = data.readInt32();
+            void *opaqueData = malloc(opaqueSize);
+            data.read(opaqueData, opaqueSize);
 
-            free(key);
-            key = NULL;
+            reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));
+
+            free(opaqueData);
+            opaqueData = NULL;
 
             return OK;
         }
 
-        case SET_ECM:
+        case DESTROY_PLUGIN:
         {
             CHECK_INTERFACE(ICrypto, data, reply);
-
-            size_t msgLength = data.readInt32();
-            void *msg = malloc(msgLength);
-            data.read(msg, msgLength);
-
-            reply->writeInt32(setEntitlementControlMessage(msg, msgLength));
-
-            free(msg);
-            msg = NULL;
+            reply->writeInt32(destroyPlugin());
 
             return OK;
         }
 
-        case DECRYPT_VIDEO:
+        case REQUIRES_SECURE_COMPONENT:
         {
             CHECK_INTERFACE(ICrypto, data, reply);
 
-            void *iv = NULL;
+            const char *mime = data.readCString();
+            reply->writeInt32(requiresSecureDecoderComponent(mime));
 
-            int32_t ivLength = data.readInt32();
-            if (ivLength >= 0) {
-                iv = malloc(ivLength);
-                data.read(iv, ivLength);
+            return OK;
+        }
+
+        case DECRYPT:
+        {
+            CHECK_INTERFACE(ICrypto, data, reply);
+
+            bool secure = data.readInt32() != 0;
+            CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
+
+            uint8_t key[16];
+            data.read(key, sizeof(key));
+
+            uint8_t iv[16];
+            data.read(iv, sizeof(iv));
+
+            size_t totalSize = data.readInt32();
+            void *srcData = malloc(totalSize);
+            data.read(srcData, totalSize);
+
+            int32_t numSubSamples = data.readInt32();
+
+            CryptoPlugin::SubSample *subSamples =
+                new CryptoPlugin::SubSample[numSubSamples];
+
+            data.read(
+                    subSamples,
+                    sizeof(CryptoPlugin::SubSample) * numSubSamples);
+
+            void *dstPtr;
+            if (secure) {
+                dstPtr = (void *)data.readIntPtr();
+            } else {
+                dstPtr = malloc(totalSize);
             }
 
-            size_t srcDataSize = data.readInt32();
-            void *srcData = malloc(srcDataSize);
-            data.read(srcData, srcDataSize);
+            status_t err = decrypt(
+                    secure,
+                    key,
+                    iv,
+                    mode,
+                    srcData,
+                    subSamples, numSubSamples,
+                    dstPtr);
 
-            void *dstData = (void *)data.readIntPtr();
-            size_t dstDataOffset = data.readInt32();
+            reply->writeInt32(err);
 
-            reply->writeInt32(
-                    decryptVideo(
-                        iv,
-                        ivLength < 0 ? 0 : ivLength,
-                        srcData,
-                        srcDataSize,
-                        dstData,
-                        dstDataOffset));
+            if (!secure) {
+                if (err == OK) {
+                    reply->write(dstPtr, totalSize);
+                }
+
+                free(dstPtr);
+                dstPtr = NULL;
+            }
+
+            delete[] subSamples;
+            subSamples = NULL;
 
             free(srcData);
             srcData = NULL;
 
-            if (iv != NULL) {
-                free(iv);
-                iv = NULL;
-            }
-
-            return OK;
-        }
-
-        case DECRYPT_AUDIO:
-        {
-            CHECK_INTERFACE(ICrypto, data, reply);
-
-            void *iv = NULL;
-
-            int32_t ivLength = data.readInt32();
-            if (ivLength >= 0) {
-                iv = malloc(ivLength);
-                data.read(iv, ivLength);
-            }
-
-            size_t srcDataSize = data.readInt32();
-            void *srcData = malloc(srcDataSize);
-            data.read(srcData, srcDataSize);
-
-            size_t dstDataSize = data.readInt32();
-            void *dstData = malloc(dstDataSize);
-
-            ssize_t res =
-                decryptAudio(
-                        iv,
-                        ivLength < 0 ? 0 : ivLength,
-                        srcData,
-                        srcDataSize,
-                        dstData,
-                        dstDataSize);
-
-            reply->writeInt32(res);
-
-            if (res > 0) {
-                reply->write(dstData, res);
-            }
-
-            free(dstData);
-            dstData = NULL;
-
-            free(srcData);
-            srcData = NULL;
-
-            if (iv != NULL) {
-                free(iv);
-                iv = NULL;
-            }
-
             return OK;
         }
 
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
index e02035f..4491f2b 100644
--- a/media/libmediaplayerservice/Crypto.cpp
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -20,46 +20,137 @@
 
 #include "Crypto.h"
 
+#include <media/hardware/CryptoAPI.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaErrors.h>
 
+#include <dlfcn.h>
+
 namespace android {
 
-Crypto::Crypto() {
+Crypto::Crypto()
+    : mInitCheck(NO_INIT),
+      mLibHandle(NULL),
+      mPlugin(NULL) {
+    mInitCheck = init();
 }
 
 Crypto::~Crypto() {
+    delete mPlugin;
+    mPlugin = NULL;
+
+    delete mFactory;
+    mFactory = NULL;
+
+    if (mLibHandle != NULL) {
+        dlclose(mLibHandle);
+        mLibHandle = NULL;
+    }
 }
 
-status_t Crypto::initialize() {
-    return ERROR_UNSUPPORTED;
+status_t Crypto::initCheck() const {
+    return mInitCheck;
 }
 
-status_t Crypto::terminate() {
-    return ERROR_UNSUPPORTED;
+status_t Crypto::init() {
+    mLibHandle = dlopen("libdrmdecrypt.so", RTLD_NOW);
+
+    if (mLibHandle == NULL) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    typedef CryptoFactory *(*CreateCryptoFactoryFunc)();
+    CreateCryptoFactoryFunc createCryptoFactory =
+        (CreateCryptoFactoryFunc)dlsym(mLibHandle, "createCryptoFactory");
+
+    if (createCryptoFactory == NULL
+            || ((mFactory = createCryptoFactory()) == NULL)) {
+        dlclose(mLibHandle);
+        mLibHandle = NULL;
+
+        return ERROR_UNSUPPORTED;
+    }
+
+    return OK;
 }
 
-status_t Crypto::setEntitlementKey(
-        const void *key, size_t keyLength) {
-    return ERROR_UNSUPPORTED;
+bool Crypto::isCryptoSchemeSupported(const uint8_t uuid[16]) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return false;
+    }
+
+    return mFactory->isCryptoSchemeSupported(uuid);
 }
 
-status_t Crypto::setEntitlementControlMessage(
-        const void *msg, size_t msgLength) {
-    return ERROR_UNSUPPORTED;
+status_t Crypto::createPlugin(
+        const uint8_t uuid[16], const void *data, size_t size) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin != NULL) {
+        return -EINVAL;
+    }
+
+    return mFactory->createPlugin(uuid, data, size, &mPlugin);
 }
 
-ssize_t Crypto::decryptVideo(
-        const void *iv, size_t ivLength,
-        const void *srcData, size_t srcDataSize,
-        void *dstData, size_t dstDataOffset) {
-    return ERROR_UNSUPPORTED;
+status_t Crypto::destroyPlugin() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    delete mPlugin;
+    mPlugin = NULL;
+
+    return OK;
 }
 
-ssize_t Crypto::decryptAudio(
-        const void *iv, size_t ivLength,
-        const void *srcData, size_t srcDataSize,
-        void *dstData, size_t dstDataSize) {
-    return ERROR_UNSUPPORTED;
+bool Crypto::requiresSecureDecoderComponent(const char *mime) const {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->requiresSecureDecoderComponent(mime);
+}
+
+status_t Crypto::decrypt(
+        bool secure,
+        const uint8_t key[16],
+        const uint8_t iv[16],
+        CryptoPlugin::Mode mode,
+        const void *srcPtr,
+        const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
+        void *dstPtr) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    return mPlugin->decrypt(
+            secure, key, iv, mode, srcPtr, subSamples, numSubSamples, dstPtr);
 }
 
 }  // namespace android
diff --git a/media/libmediaplayerservice/Crypto.h b/media/libmediaplayerservice/Crypto.h
index 9855496..74de2b5 100644
--- a/media/libmediaplayerservice/Crypto.h
+++ b/media/libmediaplayerservice/Crypto.h
@@ -23,32 +23,44 @@
 
 namespace android {
 
+struct CryptoFactory;
+struct CryptoPlugin;
+
 struct Crypto : public BnCrypto {
     Crypto();
-
-    virtual status_t initialize();
-    virtual status_t terminate();
-
-    virtual status_t setEntitlementKey(
-            const void *key, size_t keyLength);
-
-    virtual status_t setEntitlementControlMessage(
-            const void *msg, size_t msgLength);
-
-    virtual ssize_t decryptVideo(
-            const void *iv, size_t ivLength,
-            const void *srcData, size_t srcDataSize,
-            void *dstData, size_t dstDataOffset);
-
-    virtual ssize_t decryptAudio(
-            const void *iv, size_t ivLength,
-            const void *srcData, size_t srcDataSize,
-            void *dstData, size_t dstDataSize);
-
-protected:
     virtual ~Crypto();
 
+    virtual status_t initCheck() const;
+
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const;
+
+    virtual status_t createPlugin(
+            const uint8_t uuid[16], const void *data, size_t size);
+
+    virtual status_t destroyPlugin();
+
+    virtual bool requiresSecureDecoderComponent(
+            const char *mime) const;
+
+    virtual status_t decrypt(
+            bool secure,
+            const uint8_t key[16],
+            const uint8_t iv[16],
+            CryptoPlugin::Mode mode,
+            const void *srcPtr,
+            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
+            void *dstPtr);
+
 private:
+    mutable Mutex mLock;
+
+    status_t mInitCheck;
+    void *mLibHandle;
+    CryptoFactory *mFactory;
+    CryptoPlugin *mPlugin;
+
+    status_t init();
+
     DISALLOW_EVIL_CONSTRUCTORS(Crypto);
 };
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index cc3138d..8bde8f1 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -294,13 +294,7 @@
 }
 
 sp<ICrypto> MediaPlayerService::makeCrypto() {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mCrypto == NULL) {
-        mCrypto = new Crypto;
-    }
-
-    return mCrypto;
+    return new Crypto;
 }
 
 status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
@@ -1417,6 +1411,7 @@
     : mCallback(NULL),
       mCallbackCookie(NULL),
       mCallbackData(NULL),
+      mBytesWritten(0),
       mSessionId(sessionId) {
     ALOGV("AudioOutput(%d)", sessionId);
     mTrack = 0;
@@ -1495,12 +1490,19 @@
     return mMsecsPerFrame;
 }
 
-status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position)
+status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position) const
 {
     if (mTrack == 0) return NO_INIT;
     return mTrack->getPosition(position);
 }
 
+status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritten) const
+{
+    if (mTrack == 0) return NO_INIT;
+    *frameswritten = mBytesWritten / frameSize();
+    return OK;
+}
+
 status_t MediaPlayerService::AudioOutput::open(
         uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
         audio_format_t format, int bufferCount,
@@ -1615,6 +1617,10 @@
 
     mSampleRateHz = sampleRate;
     mMsecsPerFrame = mPlaybackRatePermille / (float) sampleRate;
+    uint32_t pos;
+    if (t->getPosition(&pos) == OK) {
+        mBytesWritten = uint64_t(pos) * t->frameSize();
+    }
     mTrack = t;
 
     status_t res = t->setSampleRate(mPlaybackRatePermille * mSampleRateHz / 1000);
@@ -1656,6 +1662,7 @@
         mTrack = NULL;
         mNextOutput->mSampleRateHz = mSampleRateHz;
         mNextOutput->mMsecsPerFrame = mMsecsPerFrame;
+        mNextOutput->mBytesWritten = mBytesWritten;
     }
 }
 
@@ -1666,6 +1673,7 @@
     //ALOGV("write(%p, %u)", buffer, size);
     if (mTrack) {
         ssize_t ret = mTrack->write(buffer, size);
+        mBytesWritten += ret;
         return ret;
     }
     return NO_INIT;
@@ -1777,7 +1785,7 @@
     data->unlock();
 }
 
-int MediaPlayerService::AudioOutput::getSessionId()
+int MediaPlayerService::AudioOutput::getSessionId() const
 {
     return mSessionId;
 }
@@ -1802,13 +1810,20 @@
     return mMsecsPerFrame;
 }
 
-status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position)
+status_t MediaPlayerService::AudioCache::getPosition(uint32_t *position) const
 {
     if (position == 0) return BAD_VALUE;
     *position = mSize;
     return NO_ERROR;
 }
 
+status_t MediaPlayerService::AudioCache::getFramesWritten(uint32_t *written) const
+{
+    if (written == 0) return BAD_VALUE;
+    *written = mSize;
+    return NO_ERROR;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 struct CallbackThread : public Thread {
@@ -1971,7 +1986,7 @@
     p->mSignal.signal();
 }
 
-int MediaPlayerService::AudioCache::getSessionId()
+int MediaPlayerService::AudioCache::getSessionId() const
 {
     return 0;
 }
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index b08dd6c..2a8cfd2 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -84,8 +84,9 @@
         virtual ssize_t         frameSize() const;
         virtual uint32_t        latency() const;
         virtual float           msecsPerFrame() const;
-        virtual status_t        getPosition(uint32_t *position);
-        virtual int             getSessionId();
+        virtual status_t        getPosition(uint32_t *position) const;
+        virtual status_t        getFramesWritten(uint32_t *frameswritten) const;
+        virtual int             getSessionId() const;
 
         virtual status_t        open(
                 uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
@@ -122,6 +123,7 @@
         AudioCallback           mCallback;
         void *                  mCallbackCookie;
         CallbackData *          mCallbackData;
+        uint64_t                mBytesWritten;
         audio_stream_type_t     mStreamType;
         float                   mLeftVolume;
         float                   mRightVolume;
@@ -181,8 +183,9 @@
         virtual ssize_t         frameSize() const { return ssize_t(mChannelCount * ((mFormat == AUDIO_FORMAT_PCM_16_BIT)?sizeof(int16_t):sizeof(u_int8_t))); }
         virtual uint32_t        latency() const;
         virtual float           msecsPerFrame() const;
-        virtual status_t        getPosition(uint32_t *position);
-        virtual int             getSessionId();
+        virtual status_t        getPosition(uint32_t *position) const;
+        virtual status_t        getFramesWritten(uint32_t *frameswritten) const;
+        virtual int             getSessionId() const;
 
         virtual status_t        open(
                 uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 544d501..11cea3b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -39,6 +39,7 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/SkipCutBuffer.h>
 #include <gui/ISurfaceTexture.h>
 
 #include "avc_utils.h"
@@ -63,10 +64,13 @@
       mSkipRenderingVideoUntilMediaTimeUs(-1ll),
       mVideoLateByUs(0ll),
       mNumFramesTotal(0ll),
-      mNumFramesDropped(0ll) {
+      mNumFramesDropped(0ll),
+      mSkipCutBuffer(NULL) {
 }
 
 NuPlayer::~NuPlayer() {
+    delete mSkipCutBuffer;
+    mSkipCutBuffer = NULL;
 }
 
 void NuPlayer::setUID(uid_t uid) {
@@ -234,6 +238,32 @@
 
             mSource->start();
 
+            sp<MetaData> meta = mSource->getFormat(true /* audio */);
+            if (meta != NULL) {
+                int32_t delay = 0;
+                if (!meta->findInt32(kKeyEncoderDelay, &delay)) {
+                    delay = 0;
+                }
+                int32_t padding = 0;
+                if (!meta->findInt32(kKeyEncoderPadding, &padding)) {
+                    padding = 0;
+                }
+                int32_t numchannels = 0;
+                if (delay + padding) {
+                    if (meta->findInt32(kKeyChannelCount, &numchannels)) {
+                        size_t frameSize = numchannels * sizeof(int16_t);
+                        if (mSkipCutBuffer) {
+                            size_t prevbuffersize = mSkipCutBuffer->size();
+                            if (prevbuffersize != 0) {
+                                ALOGW("Replacing SkipCutBuffer holding %d bytes", prevbuffersize);
+                            }
+                            delete mSkipCutBuffer;
+                        }
+                        mSkipCutBuffer = new SkipCutBuffer(delay * frameSize, padding * frameSize);
+                    }
+                }
+            }
+
             mRenderer = new Renderer(
                     mAudioSink,
                     new AMessage(kWhatRendererNotify, id()));
@@ -844,6 +874,10 @@
         skipUntilMediaTimeUs = -1;
     }
 
+    if (audio && mSkipCutBuffer) {
+        mSkipCutBuffer->submit(buffer);
+    }
+
     mRenderer->queueBuffer(audio, buffer, reply);
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 25766e0..f917f64 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -27,6 +27,7 @@
 struct ACodec;
 struct MetaData;
 struct NuPlayerDriver;
+class SkipCutBuffer;
 
 struct NuPlayer : public AHandler {
     NuPlayer();
@@ -128,6 +129,8 @@
     int64_t mVideoLateByUs;
     int64_t mNumFramesTotal, mNumFramesDropped;
 
+    SkipCutBuffer *mSkipCutBuffer;
+
     status_t instantiateDecoder(bool audio, sp<Decoder> *decoder);
 
     status_t feedDecoderInputData(bool audio, const sp<AMessage> &msg);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index ecbc428..1f13955 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -591,6 +591,10 @@
 void NuPlayer::Renderer::onAudioSinkChanged() {
     CHECK(!mDrainAudioQueuePending);
     mNumFramesWritten = 0;
+    uint32_t written;
+    if (mAudioSink->getFramesWritten(&written) == OK) {
+        mNumFramesWritten = written;
+    }
 }
 
 void NuPlayer::Renderer::notifyPosition() {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 42b5c7e..ced8368 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -22,10 +22,8 @@
 
 #include "include/SoftwareRenderer.h"
 
-#include <binder/IServiceManager.h>
 #include <gui/SurfaceTextureClient.h>
 #include <media/ICrypto.h>
-#include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -134,6 +132,7 @@
 status_t MediaCodec::configure(
         const sp<AMessage> &format,
         const sp<SurfaceTextureClient> &nativeWindow,
+        const sp<ICrypto> &crypto,
         uint32_t flags) {
     sp<AMessage> msg = new AMessage(kWhatConfigure, id());
 
@@ -141,13 +140,13 @@
     msg->setInt32("flags", flags);
 
     if (nativeWindow != NULL) {
-        if (!(mFlags & kFlagIsSoftwareCodec)) {
-            msg->setObject(
-                    "native-window",
-                    new NativeWindowWrapper(nativeWindow));
-        } else {
-            mNativeWindow = nativeWindow;
-        }
+        msg->setObject(
+                "native-window",
+                new NativeWindowWrapper(nativeWindow));
+    }
+
+    if (crypto != NULL) {
+        msg->setPointer("crypto", crypto.get());
     }
 
     sp<AMessage> response;
@@ -490,6 +489,12 @@
                         mFlags &= ~kFlagIsSoftwareCodec;
                     }
 
+                    if (componentName.endsWith(".secure")) {
+                        mFlags |= kFlagIsSecure;
+                    } else {
+                        mFlags &= ~kFlagIsSecure;
+                    }
+
                     (new AMessage)->postReply(mReplyID);
                     break;
                 }
@@ -532,8 +537,7 @@
                         info.mOwnedByClient = false;
                         CHECK(msg->findBuffer(name.c_str(), &info.mData));
 
-                        if (portIndex == kPortIndexInput
-                                && (mFlags & kFlagIsSecure)) {
+                        if (portIndex == kPortIndexInput && mCrypto != NULL) {
                             info.mEncryptedData =
                                 new ABuffer(info.mData->capacity());
                         }
@@ -743,8 +747,23 @@
 
             if (obj != NULL) {
                 format->setObject("native-window", obj);
+
+                if (mFlags & kFlagIsSoftwareCodec) {
+                    mNativeWindow =
+                        static_cast<NativeWindowWrapper *>(obj.get())
+                            ->getSurfaceTextureClient();
+                }
+            } else {
+                mNativeWindow.clear();
             }
 
+            void *crypto;
+            if (!msg->findPointer("crypto", &crypto)) {
+                crypto = NULL;
+            }
+
+            mCrypto = static_cast<ICrypto *>(crypto);
+
             uint32_t flags;
             CHECK(msg->findInt32("flags", (int32_t *)&flags));
 
@@ -752,59 +771,6 @@
                 format->setInt32("encoder", true);
             }
 
-            if (flags & CONFIGURE_FLAG_SECURE) {
-                mFlags |= kFlagIsSecure;
-
-                sp<IServiceManager> sm = defaultServiceManager();
-
-                sp<IBinder> binder =
-                    sm->getService(String16("media.player"));
-
-                sp<IMediaPlayerService> service =
-                    interface_cast<IMediaPlayerService>(binder);
-
-                CHECK(service != NULL);
-
-                mCrypto = service->makeCrypto();
-
-                status_t err = mCrypto->initialize();
-
-                if (err == OK) {
-                    sp<ABuffer> emm;
-                    if (format->findBuffer("emm", &emm)) {
-                        err = mCrypto->setEntitlementKey(
-                                emm->data(), emm->size());
-                    }
-                }
-
-                if (err == OK) {
-                    sp<ABuffer> ecm;
-                    if (format->findBuffer("ecm", &ecm)) {
-                        CHECK_EQ(ecm->size(), 80u);
-
-                        // bytes 16..47 of the original ecm stream data.
-                        err = mCrypto->setEntitlementControlMessage(
-                                ecm->data() + 16, 32);
-                    }
-                }
-
-                if (err != OK) {
-                    ALOGE("failed to instantiate crypto service.");
-
-                    mCrypto.clear();
-
-                    setState(INITIALIZED);
-
-                    sp<AMessage> response = new AMessage;
-                    response->setInt32("err", UNKNOWN_ERROR);
-
-                    response->postReply(mReplyID);
-                    break;
-                }
-            } else {
-                mFlags &= ~kFlagIsSecure;
-            }
-
             mCodec->initiateConfigureComponent(format);
             break;
         }
@@ -1047,8 +1013,7 @@
                 const BufferInfo &info = srcBuffers.itemAt(i);
 
                 dstBuffers->push_back(
-                        (portIndex == kPortIndexInput
-                            && (mFlags & kFlagIsSecure))
+                        (portIndex == kPortIndexInput && mCrypto != NULL)
                                 ? info.mEncryptedData : info.mData);
             }
 
@@ -1107,11 +1072,7 @@
         delete mSoftRenderer;
         mSoftRenderer = NULL;
 
-        if (mCrypto != NULL) {
-            mCrypto->terminate();
-            mCrypto.clear();
-        }
-
+        mCrypto.clear();
         mNativeWindow.clear();
 
         mOutputFormat.clear();
@@ -1221,39 +1182,41 @@
         info->mData->meta()->setInt32("csd", true);
     }
 
-    if (mFlags & kFlagIsSecure) {
-        uint8_t iv[16];
-        memset(iv, 0, sizeof(iv));
-
-        ssize_t outLength;
-
-        if (mFlags & kFlagIsSoftwareCodec) {
-            outLength = mCrypto->decryptAudio(
-                    (flags & BUFFER_FLAG_ENCRYPTED) ? iv : NULL,
-                    (flags & BUFFER_FLAG_ENCRYPTED) ? sizeof(iv) : 0,
-                        info->mEncryptedData->base() + offset,
-                        size,
-                        info->mData->base(),
-                        info->mData->capacity());
-        } else {
-            outLength = mCrypto->decryptVideo(
-                    (flags & BUFFER_FLAG_ENCRYPTED) ? iv : NULL,
-                    (flags & BUFFER_FLAG_ENCRYPTED) ? sizeof(iv) : 0,
-                        info->mEncryptedData->base() + offset,
-                        size,
-                        info->mData->base(),
-                        0  /* offset */);
-        }
-
-        if (outLength < 0) {
-            return outLength;
-        }
-
-        if ((size_t)outLength > info->mEncryptedData->capacity()) {
+    if (mCrypto != NULL) {
+        if (size > info->mEncryptedData->capacity()) {
             return -ERANGE;
         }
 
-        info->mData->setRange(0, outLength);
+        uint8_t key[16];
+        uint8_t iv[16];
+
+        CryptoPlugin::Mode mode;
+        CryptoPlugin::SubSample ss;
+        if (flags & BUFFER_FLAG_ENCRYPTED) {
+            mode = CryptoPlugin::kMode_AES_WV;
+            ss.mNumBytesOfClearData = 0;
+            ss.mNumBytesOfEncryptedData = size;
+        } else {
+            mode = CryptoPlugin::kMode_Unencrypted;
+            ss.mNumBytesOfClearData = size;
+            ss.mNumBytesOfEncryptedData = 0;
+        }
+
+        status_t err = mCrypto->decrypt(
+                (mFlags & kFlagIsSecure) != 0,
+                key,
+                iv,
+                mode,
+                info->mEncryptedData->base() + offset,
+                &ss,
+                1 /* numSubSamples */,
+                info->mData->base());
+
+        if (err != OK) {
+            return err;
+        }
+
+        info->mData->setRange(0, size);
     } else if (flags & BUFFER_FLAG_ENCRYPTED) {
         return -EINVAL;
     }
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index a31be0a..c39aa77 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -22,6 +22,8 @@
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
 #include <utils/threads.h>
 
 #include <expat.h>
@@ -448,6 +450,10 @@
     return -ENOENT;
 }
 
+size_t MediaCodecList::countCodecs() const {
+    return mCodecInfos.size();
+}
+
 const char *MediaCodecList::getCodecName(size_t index) const {
     if (index >= mCodecInfos.size()) {
         return NULL;
@@ -457,6 +463,15 @@
     return info.mName.c_str();
 }
 
+bool MediaCodecList::isEncoder(size_t index) const {
+    if (index >= mCodecInfos.size()) {
+        return NULL;
+    }
+
+    const CodecInfo &info = mCodecInfos.itemAt(index);
+    return info.mIsEncoder;
+}
+
 bool MediaCodecList::codecHasQuirk(
         size_t index, const char *quirkName) const {
     if (index >= mCodecInfos.size()) {
@@ -475,4 +490,69 @@
     return false;
 }
 
+status_t MediaCodecList::getSupportedTypes(
+        size_t index, Vector<AString> *types) const {
+    types->clear();
+
+    if (index >= mCodecInfos.size()) {
+        return -ERANGE;
+    }
+
+    const CodecInfo &info = mCodecInfos.itemAt(index);
+
+    for (size_t i = 0; i < mTypes.size(); ++i) {
+        uint32_t typeMask = 1ul << mTypes.valueAt(i);
+
+        if (info.mTypes & typeMask) {
+            types->push(mTypes.keyAt(i));
+        }
+    }
+
+    return OK;
+}
+
+status_t MediaCodecList::getCodecCapabilities(
+        size_t index, const char *type,
+        Vector<ProfileLevel> *profileLevels,
+        Vector<uint32_t> *colorFormats) const {
+    profileLevels->clear();
+    colorFormats->clear();
+
+    if (index >= mCodecInfos.size()) {
+        return -ERANGE;
+    }
+
+    const CodecInfo &info = mCodecInfos.itemAt(index);
+
+    OMXClient client;
+    status_t err = client.connect();
+    if (err != OK) {
+        return err;
+    }
+
+    CodecCapabilities caps;
+    err = QueryCodec(
+            client.interface(),
+            info.mName.c_str(), type, info.mIsEncoder, &caps);
+
+    if (err != OK) {
+        return err;
+    }
+
+    for (size_t i = 0; i < caps.mProfileLevels.size(); ++i) {
+        const CodecProfileLevel &src = caps.mProfileLevels.itemAt(i);
+
+        ProfileLevel profileLevel;
+        profileLevel.mProfile = src.mProfile;
+        profileLevel.mLevel = src.mLevel;
+        profileLevels->push(profileLevel);
+    }
+
+    for (size_t i = 0; i < caps.mColorFormats.size(); ++i) {
+        colorFormats->push(caps.mColorFormats.itemAt(i));
+    }
+
+    return OK;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index e844e36..1c4b47e 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -4509,70 +4509,84 @@
     for (size_t c = 0; c < matchingCodecs.size(); c++) {
         const char *componentName = matchingCodecs.itemAt(c).string();
 
-        if (strncmp(componentName, "OMX.", 4)) {
-            // Not an OpenMax component but a software codec.
-
-            results->push();
-            CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
-            caps->mComponentName = componentName;
-            continue;
-        }
-
-        sp<OMXCodecObserver> observer = new OMXCodecObserver;
-        IOMX::node_id node;
-        status_t err = omx->allocateNode(componentName, observer, &node);
-
-        if (err != OK) {
-            continue;
-        }
-
-        OMXCodec::setComponentRole(omx, node, !queryDecoders, mime);
-
         results->push();
         CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
-        caps->mComponentName = componentName;
 
-        OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
-        InitOMXParams(&param);
+        status_t err =
+            QueryCodec(omx, componentName, mime, !queryDecoders, caps);
 
-        param.nPortIndex = queryDecoders ? 0 : 1;
-
-        for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
-            err = omx->getParameter(
-                    node, OMX_IndexParamVideoProfileLevelQuerySupported,
-                    &param, sizeof(param));
-
-            if (err != OK) {
-                break;
-            }
-
-            CodecProfileLevel profileLevel;
-            profileLevel.mProfile = param.eProfile;
-            profileLevel.mLevel = param.eLevel;
-
-            caps->mProfileLevels.push(profileLevel);
+        if (err != OK) {
+            results->removeAt(results->size() - 1);
         }
-
-        // Color format query
-        OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
-        InitOMXParams(&portFormat);
-        portFormat.nPortIndex = queryDecoders ? 1 : 0;
-        for (portFormat.nIndex = 0;; ++portFormat.nIndex)  {
-            err = omx->getParameter(
-                    node, OMX_IndexParamVideoPortFormat,
-                    &portFormat, sizeof(portFormat));
-            if (err != OK) {
-                break;
-            }
-            caps->mColorFormats.push(portFormat.eColorFormat);
-        }
-
-        CHECK_EQ(omx->freeNode(node), (status_t)OK);
     }
 
     return OK;
 }
 
+status_t QueryCodec(
+        const sp<IOMX> &omx,
+        const char *componentName, const char *mime,
+        bool isEncoder,
+        CodecCapabilities *caps) {
+    if (strncmp(componentName, "OMX.", 4)) {
+        // Not an OpenMax component but a software codec.
+
+        caps->mComponentName = componentName;
+        return OK;
+    }
+
+    sp<OMXCodecObserver> observer = new OMXCodecObserver;
+    IOMX::node_id node;
+    status_t err = omx->allocateNode(componentName, observer, &node);
+
+    if (err != OK) {
+        return err;
+    }
+
+    OMXCodec::setComponentRole(omx, node, isEncoder, mime);
+
+    caps->mComponentName = componentName;
+
+    OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
+    InitOMXParams(&param);
+
+    param.nPortIndex = !isEncoder ? 0 : 1;
+
+    for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
+        err = omx->getParameter(
+                node, OMX_IndexParamVideoProfileLevelQuerySupported,
+                &param, sizeof(param));
+
+        if (err != OK) {
+            break;
+        }
+
+        CodecProfileLevel profileLevel;
+        profileLevel.mProfile = param.eProfile;
+        profileLevel.mLevel = param.eLevel;
+
+        caps->mProfileLevels.push(profileLevel);
+    }
+
+    // Color format query
+    OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
+    InitOMXParams(&portFormat);
+    portFormat.nPortIndex = !isEncoder ? 1 : 0;
+    for (portFormat.nIndex = 0;; ++portFormat.nIndex)  {
+        err = omx->getParameter(
+                node, OMX_IndexParamVideoPortFormat,
+                &portFormat, sizeof(portFormat));
+        if (err != OK) {
+            break;
+        }
+        caps->mColorFormats.push(portFormat.eColorFormat);
+    }
+
+    CHECK_EQ(omx->freeNode(node), (status_t)OK);
+
+    return OK;
+}
+
 status_t QueryCodecs(
         const sp<IOMX> &omx,
         const char *mimeType, bool queryDecoders,
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index bd7a226..711a8cd 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -171,6 +171,8 @@
         { "writer", METADATA_KEY_WRITER },
         { "compilation", METADATA_KEY_COMPILATION },
         { "isdrm", METADATA_KEY_IS_DRM },
+        { "width", METADATA_KEY_VIDEO_WIDTH },
+        { "height", METADATA_KEY_VIDEO_HEIGHT },
     };
     static const size_t kNumEntries = sizeof(kKeyMap) / sizeof(kKeyMap[0]);
 
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index a0db719..8c63df9 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -95,7 +95,7 @@
     void reset();
 
     void seek(
-            int64_t seekTimeUs, bool seekToKeyFrame,
+            int64_t seekTimeUs, bool isAudio,
             int64_t *actualFrameTimeUs);
 
     const mkvparser::Block *block() const;
@@ -307,51 +307,112 @@
 }
 
 void BlockIterator::seek(
-        int64_t seekTimeUs, bool seekToKeyFrame,
+        int64_t seekTimeUs, bool isAudio,
         int64_t *actualFrameTimeUs) {
     Mutex::Autolock autoLock(mExtractor->mLock);
 
     *actualFrameTimeUs = -1ll;
 
-    int64_t seekTimeNs = seekTimeUs * 1000ll;
+    const int64_t seekTimeNs = seekTimeUs * 1000ll;
 
-    mCluster = mExtractor->mSegment->FindCluster(seekTimeNs);
-    mBlockEntry = NULL;
-    mBlockEntryIndex = 0;
+    mkvparser::Segment* const pSegment = mExtractor->mSegment;
 
-    long prevKeyFrameBlockEntryIndex = -1;
+    // Special case the 0 seek to avoid loading Cues when the application
+    // extraneously seeks to 0 before playing.
+    if (seekTimeNs <= 0) {
+        ALOGV("Seek to beginning: %lld", seekTimeUs);
+        mCluster = pSegment->GetFirst();
+        mBlockEntryIndex = 0;
+        do {
+            advance_l();
+        } while (!eos() && block()->GetTrackNumber() != mTrackNum);
+        return;
+    }
+
+    ALOGV("Seeking to: %lld", seekTimeUs);
+
+    // If the Cues have not been located then find them.
+    const mkvparser::Cues* pCues = pSegment->GetCues();
+    const mkvparser::SeekHead* pSH = pSegment->GetSeekHead();
+    if (!pCues && pSH) {
+        const size_t count = pSH->GetCount();
+        const mkvparser::SeekHead::Entry* pEntry;
+        ALOGV("No Cues yet");
+
+        for (size_t index = 0; index < count; index++) {
+            pEntry = pSH->GetEntry(index);
+
+            if (pEntry->id == 0x0C53BB6B) { // Cues ID
+                long len; long long pos;
+                pSegment->ParseCues(pEntry->pos, pos, len);
+                pCues = pSegment->GetCues();
+                ALOGV("Cues found");
+                break;
+            }
+        }
+
+        if (!pCues) {
+            ALOGE("No Cues in file");
+            return;
+        }
+    }
+    else if (!pSH) {
+        ALOGE("No SeekHead");
+        return;
+    }
+
+    const mkvparser::CuePoint* pCP;
+    while (!pCues->DoneParsing()) {
+        pCues->LoadCuePoint();
+        pCP = pCues->GetLast();
+
+        if (pCP->GetTime(pSegment) >= seekTimeNs) {
+            ALOGV("Parsed past relevant Cue");
+            break;
+        }
+    }
+
+    // The Cue index is built around video keyframes
+    mkvparser::Tracks const *pTracks = pSegment->GetTracks();
+    const mkvparser::Track *pTrack = NULL;
+    for (size_t index = 0; index < pTracks->GetTracksCount(); ++index) {
+        pTrack = pTracks->GetTrackByIndex(index);
+        if (pTrack && pTrack->GetType() == 1) { // VIDEO_TRACK
+            ALOGV("Video track located at %d", index);
+            break;
+        }
+    }
+
+    // Always *search* based on the video track, but finalize based on mTrackNum
+    const mkvparser::CuePoint::TrackPosition* pTP;
+    if (pTrack && pTrack->GetType() == 1) {
+        pCues->Find(seekTimeNs, pTrack, pCP, pTP);
+    } else {
+        ALOGE("Did not locate the video track for seeking");
+        return;
+    }
+
+    mCluster = pSegment->FindOrPreloadCluster(pTP->m_pos);
+
+    CHECK(mCluster);
+    CHECK(!mCluster->EOS());
+
+    // mBlockEntryIndex starts at 0 but m_block starts at 1
+    CHECK_GT(pTP->m_block, 0);
+    mBlockEntryIndex = pTP->m_block - 1;
 
     for (;;) {
         advance_l();
 
-        if (eos()) {
+        if (eos()) break;
+
+        if (isAudio || block()->IsKey()) {
+            // Accept the first key frame
+            *actualFrameTimeUs = (block()->GetTime(mCluster) + 500LL) / 1000LL;
+            ALOGV("Requested seek point: %lld actual: %lld",
+                  seekTimeUs, actualFrameTimeUs);
             break;
         }
-
-        if (block()->GetTrackNumber() != mTrackNum) {
-            continue;
-        }
-
-        if (block()->IsKey()) {
-            prevKeyFrameBlockEntryIndex = mBlockEntryIndex - 1;
-        }
-
-        int64_t timeNs = block()->GetTime(mCluster);
-
-        if (timeNs >= seekTimeNs) {
-            *actualFrameTimeUs = (timeNs + 500ll) / 1000ll;
-            break;
-        }
-    }
-
-    if (eos()) {
-        return;
-    }
-
-    if (seekToKeyFrame && !block()->IsKey()) {
-        CHECK_GE(prevKeyFrameBlockEntryIndex, 0);
-        mBlockEntryIndex = prevKeyFrameBlockEntryIndex;
-        advance_l();
     }
 }
 
@@ -438,11 +499,11 @@
             && !mExtractor->isLiveStreaming()) {
         clearPendingFrames();
 
-        // Apparently keyframe indication in audio tracks is unreliable,
-        // fortunately in all our currently supported audio encodings every
-        // frame is effectively a keyframe.
+        // The audio we want is located by using the Cues to seek the video
+        // stream to find the target Cluster then iterating to finalize for
+        // audio.
         int64_t actualFrameTimeUs;
-        mBlockIter.seek(seekTimeUs, !mIsAudio, &actualFrameTimeUs);
+        mBlockIter.seek(seekTimeUs, mIsAudio, &actualFrameTimeUs);
 
         if (mode == ReadOptions::SEEK_CLOSEST) {
             targetSampleTimeUs = actualFrameTimeUs;
@@ -593,16 +654,12 @@
         return;
     }
 
-    if (isLiveStreaming()) {
-        ret = mSegment->ParseHeaders();
-        CHECK_EQ(ret, 0);
+    ret = mSegment->ParseHeaders();
+    CHECK_EQ(ret, 0);
 
-        long len;
-        ret = mSegment->LoadCluster(pos, len);
-        CHECK_EQ(ret, 0);
-    } else {
-        ret = mSegment->Load();
-    }
+    long len;
+    ret = mSegment->LoadCluster(pos, len);
+    CHECK_EQ(ret, 0);
 
     if (ret < 0) {
         delete mSegment;
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index 917c62a..dc5f6b8 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -75,6 +75,21 @@
             mSendSubtitleGeneration++;
             break;
         }
+        case kWhatRetryRead: {
+            int64_t seekTimeUs;
+            int seekMode;
+            if (msg->findInt64("seekTimeUs", &seekTimeUs) &&
+                msg->findInt32("seekMode", &seekMode)) {
+                MediaSource::ReadOptions options;
+                options.setSeekTo(
+                    seekTimeUs,
+                    static_cast<MediaSource::ReadOptions::SeekMode>(seekMode));
+                doRead(&options);
+            } else {
+                doRead();
+            }
+            break;
+        }
         case kWhatSeek: {
             int64_t seekTimeUs = 0;
             msg->findInt64("seekTimeUs", &seekTimeUs);
@@ -146,7 +161,15 @@
     status_t err = mSource->read(&startTimeUs, &endTimeUs,
                                  &(parcelEvent->parcel), options);
     if (err == WOULD_BLOCK) {
-        postTextEventDelayUs(NULL, kWaitTimeUsToRetryRead);
+        sp<AMessage> msg = new AMessage(kWhatRetryRead);
+        if (options != NULL) {
+            int64_t seekTimeUs;
+            MediaSource::ReadOptions::SeekMode seekMode;
+            CHECK(options->getSeekTo(&seekTimeUs, &seekMode));
+            msg->setInt64("seekTimeUs", seekTimeUs);
+            msg->setInt32("seekMode", seekMode);
+        }
+        msg->post(kWaitTimeUsToRetryRead);
         return;
     } else if (err != OK) {
         notifyError(err);
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.h b/media/libstagefright/timedtext/TimedTextPlayer.h
index 47aff03..b7e15f8 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.h
+++ b/media/libstagefright/timedtext/TimedTextPlayer.h
@@ -50,6 +50,7 @@
     enum {
         kWhatPause = 'paus',
         kWhatSeek = 'seek',
+        kWhatRetryRead = 'read',
         kWhatSendSubtitle = 'send',
         kWhatSetSource = 'ssrc',
     };
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 83af5f3..9e6a6df 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -149,13 +149,6 @@
     return rc;
 }
 
-static const char * const audio_interfaces[] = {
-    "primary",
-    "a2dp",
-    "usb",
-};
-#define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0])))
-
 // ----------------------------------------------------------------------------
 
 AudioFlinger::AudioFlinger()
@@ -191,87 +184,9 @@
         }
     }
 
-    for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
-        const hw_module_t *mod;
-        audio_hw_device_t *dev;
-
-        rc = load_audio_interface(audio_interfaces[i], &mod, &dev);
-        if (rc)
-            continue;
-
-        ALOGI("Loaded %s audio interface from %s (%s)", audio_interfaces[i],
-            mod->name, mod->id);
-        mAudioHwDevs.push(dev);
-
-        if (mPrimaryHardwareDev == NULL) {
-            mPrimaryHardwareDev = dev;
-            ALOGI("Using '%s' (%s.%s) as the primary audio interface",
-                mod->name, mod->id, audio_interfaces[i]);
-        }
-    }
-
-    if (mPrimaryHardwareDev == NULL) {
-        ALOGE("Primary audio interface not found");
-        // proceed, all later accesses to mPrimaryHardwareDev verify it's safe with initCheck()
-    }
-
-    // Currently (mPrimaryHardwareDev == NULL) == (mAudioHwDevs.size() == 0), but the way the
-    // primary HW dev is selected can change so these conditions might not always be equivalent.
-    // When that happens, re-visit all the code that assumes this.
-
-    AutoMutex lock(mHardwareLock);
-
-    // Determine the level of master volume support the primary audio HAL has,
-    // and set the initial master volume at the same time.
-    float initialVolume = 1.0;
-    mMasterVolumeSupportLvl = MVS_NONE;
-    if (0 == mPrimaryHardwareDev->init_check(mPrimaryHardwareDev)) {
-        audio_hw_device_t *dev = mPrimaryHardwareDev;
-
-        mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
-        if ((NULL != dev->get_master_volume) &&
-            (NO_ERROR == dev->get_master_volume(dev, &initialVolume))) {
-            mMasterVolumeSupportLvl = MVS_FULL;
-        } else {
-            mMasterVolumeSupportLvl = MVS_SETONLY;
-            initialVolume = 1.0;
-        }
-
-        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-        if ((NULL == dev->set_master_volume) ||
-            (NO_ERROR != dev->set_master_volume(dev, initialVolume))) {
-            mMasterVolumeSupportLvl = MVS_NONE;
-        }
-        mHardwareStatus = AUDIO_HW_IDLE;
-    }
-
-    // Set the mode for each audio HAL, and try to set the initial volume (if
-    // supported) for all of the non-primary audio HALs.
-    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
-        audio_hw_device_t *dev = mAudioHwDevs[i];
-
-        mHardwareStatus = AUDIO_HW_INIT;
-        rc = dev->init_check(dev);
-        mHardwareStatus = AUDIO_HW_IDLE;
-        if (rc == 0) {
-            mMode = AUDIO_MODE_NORMAL;  // assigned multiple times with same value
-            mHardwareStatus = AUDIO_HW_SET_MODE;
-            dev->set_mode(dev, mMode);
-
-            if ((dev != mPrimaryHardwareDev) &&
-                (NULL != dev->set_master_volume)) {
-                mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-                dev->set_master_volume(dev, initialVolume);
-            }
-
-            mHardwareStatus = AUDIO_HW_IDLE;
-        }
-    }
-
-    mMasterVolumeSW = (MVS_NONE == mMasterVolumeSupportLvl)
-                    ? initialVolume
-                    : 1.0;
-    mMasterVolume   = initialVolume;
+    mMode = AUDIO_MODE_NORMAL;
+    mMasterVolumeSW = 1.0;
+    mMasterVolume   = 1.0;
     mHardwareStatus = AUDIO_HW_IDLE;
 }
 
@@ -289,18 +204,41 @@
 
     for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
         // no mHardwareLock needed, as there are no other references to this
-        audio_hw_device_close(mAudioHwDevs[i]);
+        audio_hw_device_close(mAudioHwDevs.valueAt(i)->hwDevice());
+        delete mAudioHwDevs.valueAt(i);
     }
 }
 
-audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(uint32_t devices)
+static const char * const audio_interfaces[] = {
+    AUDIO_HARDWARE_MODULE_ID_PRIMARY,
+    AUDIO_HARDWARE_MODULE_ID_A2DP,
+    AUDIO_HARDWARE_MODULE_ID_USB,
+};
+#define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0])))
+
+audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(audio_module_handle_t module, uint32_t devices)
 {
-    /* first matching HW device is returned */
+    // if module is 0, the request comes from an old policy manager and we should load
+    // well known modules
+    if (module == 0) {
+        ALOGW("findSuitableHwDev_l() loading well know audio hw modules");
+        for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
+            loadHwModule_l(audio_interfaces[i]);
+        }
+    } else {
+        // check a match for the requested module handle
+        AudioHwDevice *audioHwdevice = mAudioHwDevs.valueFor(module);
+        if (audioHwdevice != NULL) {
+            return audioHwdevice->hwDevice();
+        }
+    }
+    // then try to find a module supporting the requested device.
     for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
-        audio_hw_device_t *dev = mAudioHwDevs[i];
+        audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
         if ((dev->get_supported_devices(dev) & devices) == devices)
             return dev;
     }
+
     return NULL;
 }
 
@@ -411,7 +349,7 @@
 
         // dump all hardware devs
         for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
-            audio_hw_device_t *dev = mAudioHwDevs[i];
+            audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
             dev->dump(dev, fd);
         }
         if (locked) mLock.unlock();
@@ -504,7 +442,7 @@
 
         bool isTimed = (flags & IAudioFlinger::TRACK_TIMED) != 0;
         track = thread->createTrack_l(client, streamType, sampleRate, format,
-                channelMask, frameCount, sharedBuffer, lSessionId, isTimed, &lStatus);
+                channelMask, frameCount, sharedBuffer, lSessionId, flags, &lStatus);
 
         // move effect chain to this output thread if an effect on same session was waiting
         // for a track to be created
@@ -610,11 +548,13 @@
 
     float swmv = value;
 
+    Mutex::Autolock _l(mLock);
+
     // when hw supports master volume, don't scale in sw mixer
     if (MVS_NONE != mMasterVolumeSupportLvl) {
         for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
             AutoMutex lock(mHardwareLock);
-            audio_hw_device_t *dev = mAudioHwDevs[i];
+            audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
 
             mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
             if (NULL != dev->set_master_volume) {
@@ -626,7 +566,6 @@
         swmv = 1.0;
     }
 
-    Mutex::Autolock _l(mLock);
     mMasterVolume   = value;
     mMasterVolumeSW = swmv;
     for (size_t i = 0; i < mPlaybackThreads.size(); i++)
@@ -853,22 +792,22 @@
 
     // ioHandle == 0 means the parameters are global to the audio hardware interface
     if (ioHandle == 0) {
+        Mutex::Autolock _l(mLock);
         status_t final_result = NO_ERROR;
         {
-        AutoMutex lock(mHardwareLock);
-        mHardwareStatus = AUDIO_HW_SET_PARAMETER;
-        for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
-            audio_hw_device_t *dev = mAudioHwDevs[i];
-            status_t result = dev->set_parameters(dev, keyValuePairs.string());
-            final_result = result ?: final_result;
-        }
-        mHardwareStatus = AUDIO_HW_IDLE;
+            AutoMutex lock(mHardwareLock);
+            mHardwareStatus = AUDIO_HW_SET_PARAMETER;
+            for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+                audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
+                status_t result = dev->set_parameters(dev, keyValuePairs.string());
+                final_result = result ?: final_result;
+            }
+            mHardwareStatus = AUDIO_HW_IDLE;
         }
         // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
         AudioParameter param = AudioParameter(keyValuePairs);
         String8 value;
         if (param.get(String8(AUDIO_PARAMETER_KEY_BT_NREC), value) == NO_ERROR) {
-            Mutex::Autolock _l(mLock);
             bool btNrecIsOff = (value == AUDIO_PARAMETER_VALUE_OFF);
             if (mBtNrecIsOff != btNrecIsOff) {
                 for (size_t i = 0; i < mRecordThreads.size(); i++) {
@@ -923,6 +862,8 @@
 //    ALOGV("getParameters() io %d, keys %s, tid %d, calling pid %d",
 //            ioHandle, keys.string(), gettid(), IPCThreadState::self()->getCallingPid());
 
+    Mutex::Autolock _l(mLock);
+
     if (ioHandle == 0) {
         String8 out_s8;
 
@@ -931,7 +872,7 @@
             {
             AutoMutex lock(mHardwareLock);
             mHardwareStatus = AUDIO_HW_GET_PARAMETER;
-            audio_hw_device_t *dev = mAudioHwDevs[i];
+            audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
             s = dev->get_parameters(dev, keys.string());
             mHardwareStatus = AUDIO_HW_IDLE;
             }
@@ -941,8 +882,6 @@
         return out_s8;
     }
 
-    Mutex::Autolock _l(mLock);
-
     PlaybackThread *playbackThread = checkPlaybackThread_l(ioHandle);
     if (playbackThread != NULL) {
         return playbackThread->getParameters(keys);
@@ -1503,8 +1442,6 @@
             stream = (audio_stream_type_t) (stream + 1)) {
         mStreamTypes[stream].volume = mAudioFlinger->streamVolume_l(stream);
         mStreamTypes[stream].mute = mAudioFlinger->streamMute_l(stream);
-        // initialized by stream_type_t default constructor
-        // mStreamTypes[stream].valid = true;
     }
     // mStreamTypes[AUDIO_STREAM_CNT] exists but isn't explicitly initialized here,
     // because mAudioFlinger doesn't have one to copy from
@@ -1608,12 +1545,50 @@
         int frameCount,
         const sp<IMemory>& sharedBuffer,
         int sessionId,
-        bool isTimed,
+        IAudioFlinger::track_flags_t flags,
         status_t *status)
 {
     sp<Track> track;
     status_t lStatus;
 
+    bool isTimed = (flags & IAudioFlinger::TRACK_TIMED) != 0;
+
+    // client expresses a preference for FAST, but we get the final say
+    if ((flags & IAudioFlinger::TRACK_FAST) &&
+          !(
+            // not timed
+            (!isTimed) &&
+            // either of these use cases:
+            (
+              // use case 1: shared buffer with any frame count
+              (
+                (sharedBuffer != 0)
+              ) ||
+              // use case 2: callback handler and small power-of-2 frame count
+              (
+                // unfortunately we can't verify that there's a callback until start()
+                // FIXME supported frame counts should not be hard-coded
+                (
+                  (frameCount == 128) ||
+                  (frameCount == 256) ||
+                  (frameCount == 512)
+                )
+              )
+            ) &&
+            // PCM data
+            audio_is_linear_pcm(format) &&
+            // mono or stereo
+            ( (channelMask == AUDIO_CHANNEL_OUT_MONO) ||
+              (channelMask == AUDIO_CHANNEL_OUT_STEREO) ) &&
+            // hardware sample rate
+            (sampleRate == mSampleRate)
+            // 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");
+        flags &= ~IAudioFlinger::TRACK_FAST;
+    }
+
     if (mType == DIRECT) {
         if ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM) {
             if (sampleRate != mSampleRate || format != mFormat || channelMask != mChannelMask) {
@@ -1661,7 +1636,7 @@
 
         if (!isTimed) {
             track = new Track(this, client, streamType, sampleRate, format,
-                    channelMask, frameCount, sharedBuffer, sessionId);
+                    channelMask, frameCount, sharedBuffer, sessionId, flags);
         } else {
             track = TimedTrack::create(this, client, streamType, sampleRate, format,
                     channelMask, frameCount, sharedBuffer, sessionId);
@@ -1679,14 +1654,6 @@
             chain->setStrategy(AudioSystem::getStrategyForStream(track->streamType()));
             chain->incTrackCnt();
         }
-
-        // invalidate track immediately if the stream type was moved to another thread since
-        // createTrack() was called by the client process.
-        if (!mStreamTypes[streamType].valid) {
-            ALOGW("createTrack_l() on thread %p: invalidating track on stream %d",
-                this, streamType);
-            android_atomic_or(CBLK_INVALID_ON, &track->mCblk->flags);
-        }
     }
     lStatus = NO_ERROR;
 
@@ -1924,7 +1891,7 @@
 }
 
 // this method must always be called either with ThreadBase mLock held or inside the thread loop
-audio_stream_t* AudioFlinger::PlaybackThread::stream()
+audio_stream_t* AudioFlinger::PlaybackThread::stream() const
 {
     if (mOutput == NULL) {
         return NULL;
@@ -1932,7 +1899,7 @@
     return &mOutput->stream->common;
 }
 
-uint32_t AudioFlinger::PlaybackThread::activeSleepTimeUs()
+uint32_t AudioFlinger::PlaybackThread::activeSleepTimeUs() const
 {
     // A2DP output latency is not due only to buffering capacity. It also reflects encoding,
     // decoding and transfer time. So sleeping for half of the latency would likely cause
@@ -2671,15 +2638,6 @@
     }
 }
 
-void AudioFlinger::PlaybackThread::setStreamValid(audio_stream_type_t streamType, bool valid)
-{
-    ALOGV ("PlaybackThread::setStreamValid() thread %p, streamType %d, valid %d",
-            this,  streamType, valid);
-    Mutex::Autolock _l(mLock);
-
-    mStreamTypes[streamType].valid = valid;
-}
-
 // getTrackName_l() must be called with ThreadBase::mLock held
 int AudioFlinger::MixerThread::getTrackName_l()
 {
@@ -2817,12 +2775,12 @@
     return NO_ERROR;
 }
 
-uint32_t AudioFlinger::MixerThread::idleSleepTimeUs()
+uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() const
 {
     return (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000) / 2;
 }
 
-uint32_t AudioFlinger::MixerThread::suspendSleepTimeUs()
+uint32_t AudioFlinger::MixerThread::suspendSleepTimeUs() const
 {
     return (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000);
 }
@@ -3166,7 +3124,7 @@
     return reconfig;
 }
 
-uint32_t AudioFlinger::DirectOutputThread::activeSleepTimeUs()
+uint32_t AudioFlinger::DirectOutputThread::activeSleepTimeUs() const
 {
     uint32_t time;
     if (audio_is_linear_pcm(mFormat)) {
@@ -3177,7 +3135,7 @@
     return time;
 }
 
-uint32_t AudioFlinger::DirectOutputThread::idleSleepTimeUs()
+uint32_t AudioFlinger::DirectOutputThread::idleSleepTimeUs() const
 {
     uint32_t time;
     if (audio_is_linear_pcm(mFormat)) {
@@ -3188,7 +3146,7 @@
     return time;
 }
 
-uint32_t AudioFlinger::DirectOutputThread::suspendSleepTimeUs()
+uint32_t AudioFlinger::DirectOutputThread::suspendSleepTimeUs() const
 {
     uint32_t time;
     if (audio_is_linear_pcm(mFormat)) {
@@ -3351,7 +3309,7 @@
     return true;
 }
 
-uint32_t AudioFlinger::DuplicatingThread::activeSleepTimeUs()
+uint32_t AudioFlinger::DuplicatingThread::activeSleepTimeUs() const
 {
     return (mWaitTimeMs * 1000) / 2;
 }
@@ -3550,7 +3508,8 @@
             uint32_t channelMask,
             int frameCount,
             const sp<IMemory>& sharedBuffer,
-            int sessionId)
+            int sessionId,
+            IAudioFlinger::track_flags_t flags)
     :   TrackBase(thread, client, sampleRate, format, channelMask, frameCount, sharedBuffer, sessionId),
     mMute(false),
     // mFillingUpStatus ?
@@ -3561,7 +3520,8 @@
     mMainBuffer(thread->mixBuffer()),
     mAuxBuffer(NULL),
     mAuxEffectId(0), mHasVolumeController(false),
-    mPresentationCompleteFrames(0)
+    mPresentationCompleteFrames(0),
+    mFlags(flags)
 {
     if (mCblk != NULL) {
         // NOTE: audio_track_cblk_t::frameSize for 8 bit PCM data is based on a sample size of
@@ -3707,6 +3667,13 @@
     status_t status = NO_ERROR;
     ALOGV("start(%d), calling pid %d session %d tid %d",
             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");
+        mFlags &= ~IAudioFlinger::TRACK_FAST;
+        // FIXME the track must be invalidated and moved to another thread or
+        // attached directly to the normal mixer now
+    }
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         Mutex::Autolock _l(thread->mLock);
@@ -3922,7 +3889,7 @@
             const sp<IMemory>& sharedBuffer,
             int sessionId)
     : Track(thread, client, streamType, sampleRate, format, channelMask,
-            frameCount, sharedBuffer, sessionId),
+            frameCount, sharedBuffer, sessionId, IAudioFlinger::TRACK_TIMED),
       mTimedSilenceBuffer(NULL),
       mTimedSilenceBufferSize(0),
       mTimedAudioOutputOnTime(false),
@@ -4400,7 +4367,8 @@
             audio_format_t format,
             uint32_t channelMask,
             int frameCount)
-    :   Track(playbackThread, NULL, AUDIO_STREAM_CNT, sampleRate, format, channelMask, frameCount, NULL, 0),
+    :   Track(playbackThread, NULL, AUDIO_STREAM_CNT, sampleRate, format, channelMask, frameCount,
+                NULL, 0, IAudioFlinger::TRACK_DEFAULT),
     mActive(false), mSourceThread(sourceThread)
 {
 
@@ -5623,7 +5591,7 @@
 }
 
 // this method must always be called either with ThreadBase mLock held or inside the thread loop
-audio_stream_t* AudioFlinger::RecordThread::stream()
+audio_stream_t* AudioFlinger::RecordThread::stream() const
 {
     if (mInput == NULL) {
         return NULL;
@@ -5634,28 +5602,84 @@
 
 // ----------------------------------------------------------------------------
 
-audio_io_handle_t AudioFlinger::openOutput(uint32_t *pDevices,
-                                uint32_t *pSamplingRate,
-                                audio_format_t *pFormat,
-                                uint32_t *pChannels,
-                                uint32_t *pLatencyMs,
-                                audio_policy_output_flags_t flags)
+audio_module_handle_t AudioFlinger::loadHwModule(const char *name)
+{
+    if (!settingsAllowed()) {
+        return 0;
+    }
+    Mutex::Autolock _l(mLock);
+    return loadHwModule_l(name);
+}
+
+// loadHwModule_l() must be called with AudioFlinger::mLock held
+audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
+{
+    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+        if (strncmp(mAudioHwDevs.valueAt(i)->moduleName(), name, strlen(name)) == 0) {
+            ALOGW("loadHwModule() module %s already loaded", name);
+            return mAudioHwDevs.keyAt(i);
+        }
+    }
+
+    const hw_module_t *mod;
+    audio_hw_device_t *dev;
+
+    int rc = load_audio_interface(name, &mod, &dev);
+    if (rc) {
+        ALOGI("loadHwModule() error %d loading module %s ", rc, name);
+        return 0;
+    }
+
+    mHardwareStatus = AUDIO_HW_INIT;
+    rc = dev->init_check(dev);
+    mHardwareStatus = AUDIO_HW_IDLE;
+    if (rc) {
+        ALOGI("loadHwModule() init check error %d for module %s ", rc, name);
+        return 0;
+    }
+
+    if ((mMasterVolumeSupportLvl != MVS_NONE) &&
+        (NULL != dev->set_master_volume)) {
+        AutoMutex lock(mHardwareLock);
+        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+        dev->set_master_volume(dev, mMasterVolume);
+        mHardwareStatus = AUDIO_HW_IDLE;
+    }
+
+    audio_module_handle_t handle = nextUniqueId();
+    mAudioHwDevs.add(handle, new AudioHwDevice(name, dev));
+
+    ALOGI("loadHwModule() Loaded %s audio interface from %s (%s) handle %d",
+          name, mod->name, mod->id, handle);
+
+    return handle;
+
+}
+
+audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
+                                           audio_devices_t *pDevices,
+                                           uint32_t *pSamplingRate,
+                                           audio_format_t *pFormat,
+                                           audio_channel_mask_t *pChannelMask,
+                                           uint32_t *pLatencyMs,
+                                           audio_policy_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;
-    uint32_t channels = pChannels ? *pChannels : 0;
+    audio_channel_mask_t channelMask = pChannelMask ? *pChannelMask : 0;
     uint32_t latency = pLatencyMs ? *pLatencyMs : 0;
     audio_stream_out_t *outStream;
     audio_hw_device_t *outHwDev;
 
-    ALOGV("openOutput(), Device %x, SamplingRate %d, Format %d, Channels %x, flags %x",
-            pDevices ? *pDevices : 0,
-            samplingRate,
-            format,
-            channels,
-            flags);
+    ALOGV("openOutput(), module %d Device %x, SamplingRate %d, Format %d, Channels %x, flags %x",
+              module,
+              pDevices ? *pDevices : 0,
+              samplingRate,
+              format,
+              channelMask,
+              flags);
 
     if (pDevices == NULL || *pDevices == 0) {
         return 0;
@@ -5663,19 +5687,19 @@
 
     Mutex::Autolock _l(mLock);
 
-    outHwDev = findSuitableHwDev_l(*pDevices);
+    outHwDev = findSuitableHwDev_l(module, *pDevices);
     if (outHwDev == NULL)
         return 0;
 
     mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
     status = outHwDev->open_output_stream(outHwDev, *pDevices, &format,
-                                          &channels, &samplingRate, &outStream);
+                                          &channelMask, &samplingRate, &outStream);
     mHardwareStatus = AUDIO_HW_IDLE;
     ALOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %d, Channels %x, status %d",
             outStream,
             samplingRate,
             format,
-            channels,
+            channelMask,
             status);
 
     if (outStream != NULL) {
@@ -5684,7 +5708,7 @@
 
         if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) ||
             (format != AUDIO_FORMAT_PCM_16_BIT) ||
-            (channels != AUDIO_CHANNEL_OUT_STEREO)) {
+            (channelMask != AUDIO_CHANNEL_OUT_STEREO)) {
             thread = new DirectOutputThread(this, output, id, *pDevices);
             ALOGV("openOutput() created direct output: ID %d thread %p", id, thread);
         } else {
@@ -5695,11 +5719,55 @@
 
         if (pSamplingRate != NULL) *pSamplingRate = samplingRate;
         if (pFormat != NULL) *pFormat = format;
-        if (pChannels != NULL) *pChannels = channels;
+        if (pChannelMask != NULL) *pChannelMask = channelMask;
         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)) {
+            ALOGI("Using module %d has the primary audio interface", module);
+            mPrimaryHardwareDev = outHwDev;
+
+            AutoMutex lock(mHardwareLock);
+            mHardwareStatus = AUDIO_HW_SET_MODE;
+            outHwDev->set_mode(outHwDev, mMode);
+
+            // Determine the level of master volume support the primary audio HAL has,
+            // and set the initial master volume at the same time.
+            float initialVolume = 1.0;
+            mMasterVolumeSupportLvl = MVS_NONE;
+
+            mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
+            if ((NULL != outHwDev->get_master_volume) &&
+                (NO_ERROR == outHwDev->get_master_volume(outHwDev, &initialVolume))) {
+                mMasterVolumeSupportLvl = MVS_FULL;
+            } else {
+                mMasterVolumeSupportLvl = MVS_SETONLY;
+                initialVolume = 1.0;
+            }
+
+            mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+            if ((NULL == outHwDev->set_master_volume) ||
+                (NO_ERROR != outHwDev->set_master_volume(outHwDev, initialVolume))) {
+                mMasterVolumeSupportLvl = MVS_NONE;
+            }
+            // now that we have a primary device, initialize master volume on other devices
+            for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+                audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
+
+                if ((dev != mPrimaryHardwareDev) &&
+                    (NULL != dev->set_master_volume)) {
+                    dev->set_master_volume(dev, initialVolume);
+                }
+            }
+            mHardwareStatus = AUDIO_HW_IDLE;
+            mMasterVolumeSW = (MVS_NONE == mMasterVolumeSupportLvl)
+                                    ? initialVolume
+                                    : 1.0;
+            mMasterVolume   = initialVolume;
+        }
         return id;
     }
 
@@ -5797,20 +5865,20 @@
     return NO_ERROR;
 }
 
-audio_io_handle_t AudioFlinger::openInput(uint32_t *pDevices,
-                                uint32_t *pSamplingRate,
-                                audio_format_t *pFormat,
-                                uint32_t *pChannels,
-                                audio_in_acoustics_t acoustics)
+audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
+                                          audio_devices_t *pDevices,
+                                          uint32_t *pSamplingRate,
+                                          audio_format_t *pFormat,
+                                          uint32_t *pChannelMask)
 {
     status_t status;
     RecordThread *thread = NULL;
     uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
     audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT;
-    uint32_t channels = pChannels ? *pChannels : 0;
+    audio_channel_mask_t channelMask = pChannelMask ? *pChannelMask : 0;
     uint32_t reqSamplingRate = samplingRate;
     audio_format_t reqFormat = format;
-    uint32_t reqChannels = channels;
+    audio_channel_mask_t reqChannels = channelMask;
     audio_stream_in_t *inStream;
     audio_hw_device_t *inHwDev;
 
@@ -5820,20 +5888,19 @@
 
     Mutex::Autolock _l(mLock);
 
-    inHwDev = findSuitableHwDev_l(*pDevices);
+    inHwDev = findSuitableHwDev_l(module, *pDevices);
     if (inHwDev == NULL)
         return 0;
 
     status = inHwDev->open_input_stream(inHwDev, *pDevices, &format,
-                                        &channels, &samplingRate,
-                                        acoustics,
+                                        &channelMask, &samplingRate,
+                                        (audio_in_acoustics_t)0,
                                         &inStream);
-    ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, acoustics %x, status %d",
+    ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, status %d",
             inStream,
             samplingRate,
             format,
-            channels,
-            acoustics,
+            channelMask,
             status);
 
     // If the input could not be opened with the requested parameters and we can handle the conversion internally,
@@ -5842,11 +5909,11 @@
     if (inStream == NULL && status == BAD_VALUE &&
         reqFormat == format && format == AUDIO_FORMAT_PCM_16_BIT &&
         (samplingRate <= 2 * reqSamplingRate) &&
-        (popcount(channels) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) {
+        (popcount(channelMask) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) {
         ALOGV("openInput() reopening with proposed sampling rate and channels");
         status = inHwDev->open_input_stream(inHwDev, *pDevices, &format,
-                                            &channels, &samplingRate,
-                                            acoustics,
+                                            &channelMask, &samplingRate,
+                                            (audio_in_acoustics_t)0,
                                             &inStream);
     }
 
@@ -5868,7 +5935,7 @@
         ALOGV("openInput() created record thread: ID %d thread %p", id, thread);
         if (pSamplingRate != NULL) *pSamplingRate = reqSamplingRate;
         if (pFormat != NULL) *pFormat = format;
-        if (pChannels != NULL) *pChannels = reqChannels;
+        if (pChannelMask != NULL) *pChannelMask = reqChannels;
 
         input->stream->common.standby(&input->stream->common);
 
@@ -5921,13 +5988,10 @@
     ALOGV("setStreamOutput() stream %d to output %d", stream, output);
     audioConfigChanged_l(AudioSystem::STREAM_CONFIG_CHANGED, output, &stream);
 
-    dstThread->setStreamValid(stream, true);
-
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
         PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
         if (thread != dstThread && thread->type() != ThreadBase::DIRECT) {
             MixerThread *srcThread = (MixerThread *)thread;
-            srcThread->setStreamValid(stream, false);
             srcThread->invalidateTracks(stream);
         }
     }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 2376aff..e493a9a 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -43,6 +43,7 @@
 
 #include <system/audio.h>
 #include <hardware/audio.h>
+#include <hardware/audio_policy.h>
 
 #include "AudioBufferProvider.h"
 
@@ -137,12 +138,13 @@
 
     virtual     size_t      getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const;
 
-    virtual audio_io_handle_t openOutput(uint32_t *pDevices,
-                                    uint32_t *pSamplingRate,
-                                    audio_format_t *pFormat,
-                                    uint32_t *pChannels,
-                                    uint32_t *pLatencyMs,
-                                    audio_policy_output_flags_t flags);
+    virtual audio_io_handle_t openOutput(audio_module_handle_t module,
+                                         audio_devices_t *pDevices,
+                                         uint32_t *pSamplingRate,
+                                         audio_format_t *pFormat,
+                                         audio_channel_mask_t *pChannelMask,
+                                         uint32_t *pLatencyMs,
+                                         audio_policy_output_flags_t flags);
 
     virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
                                                   audio_io_handle_t output2);
@@ -153,11 +155,11 @@
 
     virtual status_t restoreOutput(audio_io_handle_t output);
 
-    virtual audio_io_handle_t openInput(uint32_t *pDevices,
-                            uint32_t *pSamplingRate,
-                            audio_format_t *pFormat,
-                            uint32_t *pChannels,
-                            audio_in_acoustics_t acoustics);
+    virtual audio_io_handle_t openInput(audio_module_handle_t module,
+                                        audio_devices_t *pDevices,
+                                        uint32_t *pSamplingRate,
+                                        audio_format_t *pFormat,
+                                        audio_channel_mask_t *pChannelMask);
 
     virtual status_t closeInput(audio_io_handle_t input);
 
@@ -196,6 +198,8 @@
     virtual status_t moveEffects(int sessionId, audio_io_handle_t srcOutput,
                         audio_io_handle_t dstOutput);
 
+    virtual audio_module_handle_t loadHwModule(const char *name);
+
     virtual     status_t    onTransact(
                                 uint32_t code,
                                 const Parcel& data,
@@ -256,7 +260,7 @@
     // RefBase
     virtual     void        onFirstRef();
 
-    audio_hw_device_t*      findSuitableHwDev_l(uint32_t devices);
+    audio_hw_device_t*      findSuitableHwDev_l(audio_module_handle_t module, uint32_t devices);
     void                    purgeStaleEffects_l();
 
     // standby delay for MIXER and DUPLICATING playback threads is read from property
@@ -472,7 +476,7 @@
                     audio_io_handle_t id() const { return mId;}
                     bool        standby() const { return mStandby; }
                     uint32_t    device() const { return mDevice; }
-        virtual     audio_stream_t* stream() = 0;
+        virtual     audio_stream_t* stream() const = 0;
 
                     sp<EffectHandle> createEffect_l(
                                         const sp<AudioFlinger::Client>& client,
@@ -630,13 +634,11 @@
     struct  stream_type_t {
         stream_type_t()
             :   volume(1.0f),
-                mute(false),
-                valid(true)
+                mute(false)
         {
         }
         float       volume;
         bool        mute;
-        bool        valid;
     };
 
     // --- PlaybackThread ---
@@ -662,7 +664,8 @@
                                         uint32_t channelMask,
                                         int frameCount,
                                         const sp<IMemory>& sharedBuffer,
-                                        int sessionId);
+                                        int sessionId,
+                                        IAudioFlinger::track_flags_t flags);
             virtual             ~Track();
 
                     void        dump(char* buffer, size_t size);
@@ -689,6 +692,9 @@
                     int16_t     *mainBuffer() const { return mMainBuffer; }
                     int         auxEffectId() const { return mAuxEffectId; }
 
+                    bool        isFastTrack() const
+                            { return (mFlags & IAudioFlinger::TRACK_FAST) != 0; }
+
         protected:
             // for numerous
             friend class PlaybackThread;
@@ -742,6 +748,8 @@
             bool                mHasVolumeController;
             size_t              mPresentationCompleteFrames; // number of frames written to the audio HAL
                                                        // when this track will be fully rendered
+        private:
+            IAudioFlinger::track_flags_t mFlags;
         };  // end of Track
 
         class TimedTrack : public Track {
@@ -913,12 +921,12 @@
                                     int frameCount,
                                     const sp<IMemory>& sharedBuffer,
                                     int sessionId,
-                                    bool isTimed,
+                                    IAudioFlinger::track_flags_t flags,
                                     status_t *status);
 
                     AudioStreamOut* getOutput() const;
                     AudioStreamOut* clearOutput();
-                    virtual audio_stream_t* stream();
+                    virtual audio_stream_t* stream() const;
 
                     void        suspend() { mSuspended++; }
                     void        restore() { if (mSuspended > 0) mSuspended--; }
@@ -939,7 +947,6 @@
                     virtual uint32_t hasAudioSession(int sessionId);
                     virtual uint32_t getStrategyForSession_l(int sessionId);
 
-                            void setStreamValid(audio_stream_type_t streamType, bool valid);
 
                     virtual status_t setSyncEvent(const sp<SyncEvent>& event);
                     virtual bool     isValidSyncEvent(const sp<SyncEvent>& event);
@@ -960,9 +967,13 @@
         // Allocate a track name.  Returns name >= 0 if successful, -1 on failure.
         virtual int             getTrackName_l() = 0;
         virtual void            deleteTrackName_l(int name) = 0;
-        virtual uint32_t        activeSleepTimeUs();
-        virtual uint32_t        idleSleepTimeUs() = 0;
-        virtual uint32_t        suspendSleepTimeUs() = 0;
+
+        // Time to sleep between cycles when:
+        virtual uint32_t        activeSleepTimeUs() const;      // mixer state MIXER_TRACKS_ENABLED
+        virtual uint32_t        idleSleepTimeUs() const = 0;    // mixer state MIXER_IDLE
+        virtual uint32_t        suspendSleepTimeUs() const = 0; // audio policy manager suspended us
+        // No sleep when mixer state == MIXER_TRACKS_READY; relies on audio HAL stream->write()
+        // No sleep in standby mode; waits on a condition
 
         // Code snippets that are temporarily lifted up out of threadLoop() until the merge
                     void        checkSilentMode_l();
@@ -1048,8 +1059,8 @@
         virtual     mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
         virtual     int         getTrackName_l();
         virtual     void        deleteTrackName_l(int name);
-        virtual     uint32_t    idleSleepTimeUs();
-        virtual     uint32_t    suspendSleepTimeUs();
+        virtual     uint32_t    idleSleepTimeUs() const;
+        virtual     uint32_t    suspendSleepTimeUs() const;
         virtual     void        cacheParameters_l();
 
         // threadLoop snippets
@@ -1073,9 +1084,9 @@
     protected:
         virtual     int         getTrackName_l();
         virtual     void        deleteTrackName_l(int name);
-        virtual     uint32_t    activeSleepTimeUs();
-        virtual     uint32_t    idleSleepTimeUs();
-        virtual     uint32_t    suspendSleepTimeUs();
+        virtual     uint32_t    activeSleepTimeUs() const;
+        virtual     uint32_t    idleSleepTimeUs() const;
+        virtual     uint32_t    suspendSleepTimeUs() const;
         virtual     void        cacheParameters_l();
 
         // threadLoop snippets
@@ -1110,9 +1121,9 @@
         // Thread virtuals
                     void        addOutputTrack(MixerThread* thread);
                     void        removeOutputTrack(MixerThread* thread);
-                    uint32_t    waitTimeMs() { return mWaitTimeMs; }
+                    uint32_t    waitTimeMs() const { return mWaitTimeMs; }
     protected:
-        virtual     uint32_t    activeSleepTimeUs();
+        virtual     uint32_t    activeSleepTimeUs() const;
 
     private:
                     bool        outputsReady(const SortedVector< sp<OutputTrack> > &outputTracks);
@@ -1260,7 +1271,7 @@
                 status_t    dump(int fd, const Vector<String16>& args);
                 AudioStreamIn* getInput() const;
                 AudioStreamIn* clearInput();
-                virtual audio_stream_t* stream();
+                virtual audio_stream_t* stream() const;
 
         // AudioBufferProvider interface
         virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts);
@@ -1692,15 +1703,30 @@
         MVS_FULL,
     };
 
+    class AudioHwDevice {
+    public:
+        AudioHwDevice(const char *moduleName, audio_hw_device_t *hwDevice) :
+            mModuleName(strdup(moduleName)), mHwDevice(hwDevice){}
+        ~AudioHwDevice() { free((void *)mModuleName); }
+
+        const char *moduleName() const { return mModuleName; }
+        audio_hw_device_t *hwDevice() const { return mHwDevice; }
+    private:
+        const char * const mModuleName;
+        audio_hw_device_t * const mHwDevice;
+    };
+
     mutable     Mutex                               mLock;
 
                 DefaultKeyedVector< pid_t, wp<Client> >     mClients;   // see ~Client()
 
                 mutable     Mutex                   mHardwareLock;
+                // NOTE: If both mLock and mHardwareLock mutexes must be held,
+                // always take mLock before mHardwareLock
 
                 // These two fields are immutable after onFirstRef(), so no lock needed to access
                 audio_hw_device_t*                  mPrimaryHardwareDev; // mAudioHwDevs[0] or NULL
-                Vector<audio_hw_device_t*>          mAudioHwDevs;
+                DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*>  mAudioHwDevs;
 
     // for dump, indicates which hardware operation is currently in progress (but not stream ops)
     enum hardware_call_state {
@@ -1750,6 +1776,7 @@
                 float       masterVolume_l() const;
                 float       masterVolumeSW_l() const  { return mMasterVolumeSW; }
                 bool        masterMute_l() const    { return mMasterMute; }
+                audio_module_handle_t loadHwModule_l(const char *name);
 
                 Vector < sp<SyncEvent> > mPendingSyncEvents; // sync events awaiting for a session
                                                              // to be created
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 3f4c19a..0e6ea12 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -66,32 +66,7 @@
     // and mTrackNames is initially 0.  However, leave it here until that's verified.
     track_t* t = mState.tracks;
     for (unsigned i=0 ; i < MAX_NUM_TRACKS ; i++) {
-        t->needs = 0;
-        t->volume[0] = UNITY_GAIN;
-        t->volume[1] = UNITY_GAIN;
-        // no initialization needed
-        // t->prevVolume[0]
-        // t->prevVolume[1]
-        t->volumeInc[0] = 0;
-        t->volumeInc[1] = 0;
-        t->auxLevel = 0;
-        t->auxInc = 0;
-        // no initialization needed
-        // t->prevAuxLevel
-        // t->frameCount
-        t->channelCount = 2;
-        t->enabled = false;
-        t->format = 16;
-        t->channelMask = AUDIO_CHANNEL_OUT_STEREO;
-        t->bufferProvider = NULL;
-        t->buffer.raw = NULL;
-        // t->buffer.frameCount
-        t->hook = NULL;
-        t->in = NULL;
-        t->resampler = NULL;
-        t->sampleRate = mSampleRate;
-        t->mainBuffer = NULL;
-        t->auxBuffer = NULL;
+        // FIXME redundant per track
         t->localTimeFreq = lc.getLocalFreq();
         t++;
     }
@@ -115,6 +90,38 @@
         int n = __builtin_ctz(names);
         ALOGV("add track (%d)", n);
         mTrackNames |= 1 << n;
+        // assume default parameters for the track, except where noted below
+        track_t* t = &mState.tracks[n];
+        t->needs = 0;
+        t->volume[0] = UNITY_GAIN;
+        t->volume[1] = UNITY_GAIN;
+        // no initialization needed
+        // t->prevVolume[0]
+        // t->prevVolume[1]
+        t->volumeInc[0] = 0;
+        t->volumeInc[1] = 0;
+        t->auxLevel = 0;
+        t->auxInc = 0;
+        // no initialization needed
+        // t->prevAuxLevel
+        // t->frameCount
+        t->channelCount = 2;
+        t->enabled = false;
+        t->format = 16;
+        t->channelMask = AUDIO_CHANNEL_OUT_STEREO;
+        // setBufferProvider(name, AudioBufferProvider *) is required before enable(name)
+        t->bufferProvider = NULL;
+        t->buffer.raw = NULL;
+        // no initialization needed
+        // t->buffer.frameCount
+        t->hook = NULL;
+        t->in = NULL;
+        t->resampler = NULL;
+        t->sampleRate = mSampleRate;
+        // setParameter(name, TRACK, MAIN_BUFFER, mixBuffer) is required before enable(name)
+        t->mainBuffer = NULL;
+        t->auxBuffer = NULL;
+        // see t->localTimeFreq in constructor above
         return TRACK0 + n;
     }
     return -1;
@@ -215,6 +222,9 @@
                 invalidateState(1 << name);
             }
             break;
+        case FORMAT:
+            ALOG_ASSERT(valueInt == AUDIO_FORMAT_PCM_16_BIT);
+            break;
         default:
             LOG_FATAL("bad param");
         }
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index c23eb04..15f4349 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -31,7 +31,6 @@
 #include <utils/threads.h>
 #include "AudioPolicyService.h"
 #include "ServiceUtilities.h"
-#include <cutils/properties.h>
 #include <hardware_legacy/power.h>
 #include <media/AudioEffect.h>
 #include <media/EffectsFactoryApi.h>
@@ -1330,13 +1329,9 @@
 /* implementation of the interface to the policy manager */
 extern "C" {
 
-static audio_io_handle_t aps_open_output(void *service,
-                                             uint32_t *pDevices,
-                                             uint32_t *pSamplingRate,
-                                             audio_format_t *pFormat,
-                                             uint32_t *pChannels,
-                                             uint32_t *pLatencyMs,
-                                             audio_policy_output_flags_t flags)
+
+static audio_module_handle_t aps_load_hw_module(void *service,
+                                             const char *name)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
@@ -1344,7 +1339,44 @@
         return 0;
     }
 
-    return af->openOutput(pDevices, pSamplingRate, pFormat, pChannels,
+    return af->loadHwModule(name);
+}
+
+// deprecated: replaced by aps_open_output_on_module()
+static audio_io_handle_t aps_open_output(void *service,
+                                         audio_devices_t *pDevices,
+                                         uint32_t *pSamplingRate,
+                                         audio_format_t *pFormat,
+                                         audio_channel_mask_t *pChannelMask,
+                                         uint32_t *pLatencyMs,
+                                         audio_policy_output_flags_t flags)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return 0;
+    }
+
+    return af->openOutput((audio_module_handle_t)0, pDevices, pSamplingRate, pFormat, pChannelMask,
+                          pLatencyMs, flags);
+}
+
+static audio_io_handle_t aps_open_output_on_module(void *service,
+                                                   audio_module_handle_t module,
+                                                   audio_devices_t *pDevices,
+                                                   uint32_t *pSamplingRate,
+                                                   audio_format_t *pFormat,
+                                                   audio_channel_mask_t *pChannelMask,
+                                                   uint32_t *pLatencyMs,
+                                                   audio_policy_output_flags_t flags)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return 0;
+    }
+    ALOGW("%s: %d", __func__, module);
+    return af->openOutput(module, pDevices, pSamplingRate, pFormat, pChannelMask,
                           pLatencyMs, flags);
 }
 
@@ -1391,12 +1423,13 @@
     return af->restoreOutput(output);
 }
 
+// deprecated: replaced by aps_open_input_on_module()
 static audio_io_handle_t aps_open_input(void *service,
-                                            uint32_t *pDevices,
-                                            uint32_t *pSamplingRate,
-                                            audio_format_t *pFormat,
-                                            uint32_t *pChannels,
-                                            audio_in_acoustics_t acoustics)
+                                        audio_devices_t *pDevices,
+                                        uint32_t *pSamplingRate,
+                                        audio_format_t *pFormat,
+                                        audio_channel_mask_t *pChannelMask,
+                                        audio_in_acoustics_t acoustics)
 {
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af == 0) {
@@ -1404,8 +1437,23 @@
         return 0;
     }
 
-    return af->openInput(pDevices, pSamplingRate, pFormat, pChannels,
-                         acoustics);
+    return af->openInput((audio_module_handle_t)0, pDevices, pSamplingRate, pFormat, pChannelMask);
+}
+
+static audio_io_handle_t aps_open_input_on_module(void *service,
+                                                  audio_module_handle_t module,
+                                                  audio_devices_t *pDevices,
+                                                  uint32_t *pSamplingRate,
+                                                  audio_format_t *pFormat,
+                                                  audio_channel_mask_t *pChannelMask)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return 0;
+    }
+
+    return af->openInput(module, pDevices, pSamplingRate, pFormat, pChannelMask);
 }
 
 static int aps_close_input(void *service, audio_io_handle_t input)
@@ -1504,6 +1552,9 @@
         stop_tone             : aps_stop_tone,
         set_voice_volume      : aps_set_voice_volume,
         move_effects          : aps_move_effects,
+        load_hw_module        : aps_load_hw_module,
+        open_output_on_module : aps_open_output_on_module,
+        open_input_on_module  : aps_open_input_on_module,
     };
 }; // namespace <unnamed>