Merge "cameraservice: disallow zsl/recording coexistentce" into lmp-dev
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
index bfbc6bf..27df9cd 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -104,6 +104,10 @@
         return android::ERROR_DRM_CANNOT_HANDLE;
     }
 
+    virtual status_t unprovisionDevice() {
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
     virtual status_t getSecureStops(List<Vector<uint8_t> >& secureStops) {
         UNUSED(secureStops);
         return android::ERROR_DRM_CANNOT_HANDLE;
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
index 6efc712..2ea554b 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
@@ -299,6 +299,12 @@
         return OK;
     }
 
+    status_t MockDrmPlugin::unprovisionDevice()
+    {
+        ALOGD("MockDrmPlugin::unprovisionDevice()");
+        return OK;
+    }
+
     status_t MockDrmPlugin::getSecureStops(List<Vector<uint8_t> > &secureStops)
     {
         Mutex::Autolock lock(mLock);
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
index 97d7052..4b63299 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
@@ -85,6 +85,8 @@
                                           Vector<uint8_t> &certificate,
                                           Vector<uint8_t> &wrappedKey);
 
+        status_t unprovisionDevice();
+
         status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
         status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
 
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index cf34991..f22792f 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -309,6 +309,12 @@
     /* Set audio port configuration */
     static status_t setAudioPortConfig(const struct audio_port_config *config);
 
+
+    static status_t acquireSoundTriggerSession(audio_session_t *session,
+                                           audio_io_handle_t *ioHandle,
+                                           audio_devices_t *device);
+    static status_t releaseSoundTriggerSession(audio_session_t session);
+
     // ----------------------------------------------------------------------------
 
     class AudioPortCallback : public RefBase
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index abbda32..c251439 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -136,6 +136,12 @@
     virtual status_t setAudioPortConfig(const struct audio_port_config *config) = 0;
 
     virtual void registerClient(const sp<IAudioPolicyServiceClient>& client) = 0;
+
+    virtual status_t acquireSoundTriggerSession(audio_session_t *session,
+                                           audio_io_handle_t *ioHandle,
+                                           audio_devices_t *device) = 0;
+
+    virtual status_t releaseSoundTriggerSession(audio_session_t session) = 0;
 };
 
 
diff --git a/include/media/IDrm.h b/include/media/IDrm.h
index 32ae28e..68de87a 100644
--- a/include/media/IDrm.h
+++ b/include/media/IDrm.h
@@ -70,6 +70,8 @@
                                               Vector<uint8_t> &certificate,
                                               Vector<uint8_t> &wrappedKey) = 0;
 
+    virtual status_t unprovisionDevice() = 0;
+
     virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) = 0;
 
     virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) = 0;
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 7e4a1d9..a68adea 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -251,7 +251,7 @@
     status_t setupAACCodec(
             bool encoder,
             int32_t numChannels, int32_t sampleRate, int32_t bitRate,
-            int32_t aacProfile, bool isADTS);
+            int32_t aacProfile, bool isADTS, int32_t sbrMode);
 
     status_t setupAC3Codec(bool encoder, int32_t numChannels, int32_t sampleRate);
 
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
index 4b18a0b..e1b2830 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -106,7 +106,6 @@
     bool mStarted;
     bool mStopping;
     bool mDoMoreWorkPending;
-    bool mPullerReachedEOS;
     sp<AMessage> mEncoderActivityNotify;
     sp<IGraphicBufferProducer> mGraphicBufferProducer;
     Vector<sp<ABuffer> > mEncoderInputBuffers;
@@ -123,7 +122,7 @@
     Mutex mOutputBufferLock;
     Condition mOutputBufferCond;
     List<MediaBuffer*> mOutputBufferQueue;
-    bool mEncodedReachedEOS;
+    bool mEncoderReachedEOS;
     status_t mErrorCode;
 
     DISALLOW_EVIL_CONSTRUCTORS(MediaCodecSource);
diff --git a/include/soundtrigger/ISoundTriggerClient.h b/include/soundtrigger/ISoundTriggerClient.h
index 7f86d02..480429a 100644
--- a/include/soundtrigger/ISoundTriggerClient.h
+++ b/include/soundtrigger/ISoundTriggerClient.h
@@ -31,6 +31,10 @@
 
     virtual void onRecognitionEvent(const sp<IMemory>& eventMemory) = 0;
 
+    virtual void onSoundModelEvent(const sp<IMemory>& eventMemory) = 0;
+
+    virtual void onServiceStateChange(const sp<IMemory>& eventMemory) = 0;
+
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/soundtrigger/ISoundTriggerHwService.h b/include/soundtrigger/ISoundTriggerHwService.h
index 05a764a..ae0cb01 100644
--- a/include/soundtrigger/ISoundTriggerHwService.h
+++ b/include/soundtrigger/ISoundTriggerHwService.h
@@ -39,6 +39,8 @@
     virtual status_t attach(const sound_trigger_module_handle_t handle,
                                       const sp<ISoundTriggerClient>& client,
                                       sp<ISoundTrigger>& module) = 0;
+
+    virtual status_t setCaptureState(bool active) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/soundtrigger/SoundTrigger.h b/include/soundtrigger/SoundTrigger.h
index 1f7f286..bf5e1de 100644
--- a/include/soundtrigger/SoundTrigger.h
+++ b/include/soundtrigger/SoundTrigger.h
@@ -18,6 +18,7 @@
 #define ANDROID_HARDWARE_SOUNDTRIGGER_H
 
 #include <binder/IBinder.h>
+#include <utils/threads.h>
 #include <soundtrigger/SoundTriggerCallback.h>
 #include <soundtrigger/ISoundTrigger.h>
 #include <soundtrigger/ISoundTriggerHwService.h>
@@ -32,12 +33,15 @@
                         public IBinder::DeathRecipient
 {
 public:
+
+    virtual ~SoundTrigger();
+
     static  status_t listModules(struct sound_trigger_module_descriptor *modules,
                                  uint32_t *numModules);
     static  sp<SoundTrigger> attach(const sound_trigger_module_handle_t module,
                                        const sp<SoundTriggerCallback>& callback);
 
-            virtual ~SoundTrigger();
+    static  status_t setCaptureState(bool active);
 
             void detach();
 
@@ -51,6 +55,8 @@
 
             // BpSoundTriggerClient
             virtual void onRecognitionEvent(const sp<IMemory>& eventMemory);
+            virtual void onSoundModelEvent(const sp<IMemory>& eventMemory);
+            virtual void onServiceStateChange(const sp<IMemory>& eventMemory);
 
             //IBinder::DeathRecipient
             virtual void binderDied(const wp<IBinder>& who);
diff --git a/include/soundtrigger/SoundTriggerCallback.h b/include/soundtrigger/SoundTriggerCallback.h
index 8a5ba02..b5277f2 100644
--- a/include/soundtrigger/SoundTriggerCallback.h
+++ b/include/soundtrigger/SoundTriggerCallback.h
@@ -31,6 +31,10 @@
 
     virtual void onRecognitionEvent(struct sound_trigger_recognition_event *event) = 0;
 
+    virtual void onSoundModelEvent(struct sound_trigger_model_event *event) = 0;
+
+    virtual void onServiceStateChange(sound_trigger_service_state_t state) = 0;
+
     virtual void onServiceDied() = 0;
 
 };
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 365a594..172b056 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -913,6 +913,21 @@
     gAudioPortCallback = callBack;
 }
 
+status_t AudioSystem::acquireSoundTriggerSession(audio_session_t *session,
+                                       audio_io_handle_t *ioHandle,
+                                       audio_devices_t *device)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->acquireSoundTriggerSession(session, ioHandle, device);
+}
+
+status_t AudioSystem::releaseSoundTriggerSession(audio_session_t session)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->releaseSoundTriggerSession(session);
+}
 // ---------------------------------------------------------------------------
 
 void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused)
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 1593b17..b57f747 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -65,7 +65,9 @@
     LIST_AUDIO_PATCHES,
     SET_AUDIO_PORT_CONFIG,
     REGISTER_CLIENT,
-    GET_OUTPUT_FOR_ATTR
+    GET_OUTPUT_FOR_ATTR,
+    ACQUIRE_SOUNDTRIGGER_SESSION,
+    RELEASE_SOUNDTRIGGER_SESSION
 };
 
 class BpAudioPolicyService : public BpInterface<IAudioPolicyService>
@@ -563,6 +565,7 @@
         }
         return status;
     }
+
     virtual void registerClient(const sp<IAudioPolicyServiceClient>& client)
     {
         Parcel data, reply;
@@ -570,6 +573,40 @@
         data.writeStrongBinder(client->asBinder());
         remote()->transact(REGISTER_CLIENT, data, &reply);
     }
+
+    virtual status_t acquireSoundTriggerSession(audio_session_t *session,
+                                            audio_io_handle_t *ioHandle,
+                                            audio_devices_t *device)
+    {
+        if (session == NULL || ioHandle == NULL || device == NULL) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        status_t status = remote()->transact(ACQUIRE_SOUNDTRIGGER_SESSION, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = (status_t)reply.readInt32();
+        if (status == NO_ERROR) {
+            *session = (audio_session_t)reply.readInt32();
+            *ioHandle = (audio_io_handle_t)reply.readInt32();
+            *device = (audio_devices_t)reply.readInt32();
+        }
+        return status;
+    }
+
+    virtual status_t releaseSoundTriggerSession(audio_session_t session)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(session);
+        status_t status = remote()->transact(RELEASE_SOUNDTRIGGER_SESSION, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        return (status_t)reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -984,6 +1021,7 @@
             reply->writeInt32(status);
             return NO_ERROR;
         }
+
         case REGISTER_CLIENT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             sp<IAudioPolicyServiceClient> client = interface_cast<IAudioPolicyServiceClient>(
@@ -992,6 +1030,33 @@
             return NO_ERROR;
         } break;
 
+        case ACQUIRE_SOUNDTRIGGER_SESSION: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            sp<IAudioPolicyServiceClient> client = interface_cast<IAudioPolicyServiceClient>(
+                    data.readStrongBinder());
+            audio_session_t session;
+            audio_io_handle_t ioHandle;
+            audio_devices_t device;
+            status_t status = acquireSoundTriggerSession(&session, &ioHandle, &device);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->writeInt32(session);
+                reply->writeInt32(ioHandle);
+                reply->writeInt32(device);
+            }
+            return NO_ERROR;
+        } break;
+
+        case RELEASE_SOUNDTRIGGER_SESSION: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            sp<IAudioPolicyServiceClient> client = interface_cast<IAudioPolicyServiceClient>(
+                    data.readStrongBinder());
+            audio_session_t session = (audio_session_t)data.readInt32();
+            status_t status = releaseSoundTriggerSession(session);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
index f1a6a9f..1904839 100644
--- a/media/libmedia/IDrm.cpp
+++ b/media/libmedia/IDrm.cpp
@@ -53,7 +53,8 @@
     SIGN,
     SIGN_RSA,
     VERIFY,
-    SET_LISTENER
+    SET_LISTENER,
+    UNPROVISION_DEVICE
 };
 
 struct BpDrm : public BpInterface<IDrm> {
@@ -229,6 +230,15 @@
         return reply.readInt32();
     }
 
+    virtual status_t unprovisionDevice() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+        remote()->transact(UNPROVISION_DEVICE, data, &reply);
+
+        return reply.readInt32();
+    }
+
     virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) {
         Parcel data, reply;
         data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
@@ -619,6 +629,14 @@
             return OK;
         }
 
+        case UNPROVISION_DEVICE:
+        {
+            CHECK_INTERFACE(IDrm, data, reply);
+            status_t result = unprovisionDevice();
+            reply->writeInt32(result);
+            return OK;
+        }
+
         case GET_SECURE_STOPS:
         {
             CHECK_INTERFACE(IDrm, data, reply);
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index d50037f..d222316 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -417,6 +417,23 @@
     return mPlugin->provideProvisionResponse(response, certificate, wrappedKey);
 }
 
+status_t Drm::unprovisionDevice() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mPlugin == NULL) {
+        return -EINVAL;
+    }
+
+    if (!checkPermission("android.permission.REMOVE_DRM_CERTIFICATES")) {
+        return -EPERM;
+    }
+
+    return mPlugin->unprovisionDevice();
+}
 
 status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
     Mutex::Autolock autoLock(mLock);
diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h
index 3d4b0fc..9e23e2e 100644
--- a/media/libmediaplayerservice/Drm.h
+++ b/media/libmediaplayerservice/Drm.h
@@ -75,6 +75,8 @@
                                               Vector<uint8_t> &certificate,
                                               Vector<uint8_t> &wrappedKey);
 
+    virtual status_t unprovisionDevice();
+
     virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
 
     virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index a3e84df..32842bb 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "GenericSource"
+
 #include "GenericSource.h"
 
 #include "AnotherPacketSource.h"
@@ -65,7 +68,9 @@
       mFetchTimedTextDataGeneration(0),
       mDurationUs(0ll),
       mAudioIsVorbis(false),
-      mIsWidevine(false) {
+      mIsWidevine(false),
+      mUIDValid(false),
+      mUID(0) {
     DataSource::RegisterDefaultSniffers();
 
     sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
@@ -134,6 +139,12 @@
             if (mVideoTrack.mSource == NULL) {
                 mVideoTrack.mIndex = i;
                 mVideoTrack.mSource = track;
+
+                // check if the source requires secure buffers
+                int32_t secure;
+                if (meta->findInt32(kKeyRequiresSecureBuffers, &secure) && secure) {
+                    mIsWidevine = true;
+                }
             }
         }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 58d0138..17038a4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -227,7 +227,9 @@
     } else if ((!strncasecmp(url, "widevine://", 11))) {
         source = new GenericSource(notify, httpService, url, headers,
                 true /* isWidevine */, mUIDValid, mUID);
-        mSourceFlags |= Source::FLAG_SECURE;
+        // Don't set FLAG_SECURE on mSourceFlags here, the correct flags
+        // will be updated in Source::kWhatFlagsChanged handler when
+        // GenericSource is prepared.
     } else {
         source = new GenericSource(notify, httpService, url, headers);
     }
@@ -749,6 +751,15 @@
                             ALOGV("Mime \"%s\" mapped to audio_format 0x%x",
                                     mime.c_str(), audioFormat);
 
+                            int32_t aacProfile = -1;
+                            if (audioFormat == AUDIO_FORMAT_AAC
+                                    && format->findInt32("aac-profile", &aacProfile)) {
+                                // Redefine AAC format as per aac profile
+                                mapAACProfileToAudioFormat(
+                                        audioFormat,
+                                        aacProfile);
+                            }
+
                             flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
 
                             offloadInfo.duration_us = -1;
@@ -1169,11 +1180,11 @@
     sp<AMessage> reply;
     CHECK(msg->findMessage("reply", &reply));
 
-    if ((audio && IsFlushingState(mFlushingAudio))
-            || (!audio && IsFlushingState(mFlushingVideo))) {
-        reply->setInt32("err", INFO_DISCONTINUITY);
-        reply->post();
-        return OK;
+    if ((audio && mFlushingAudio != NONE
+                && mFlushingAudio != AWAITING_DISCONTINUITY)
+            || (!audio && mFlushingVideo != NONE
+                       && mFlushingVideo != AWAITING_DISCONTINUITY)) {
+        return -EWOULDBLOCK;
     }
 
     sp<ABuffer> accessUnit;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 5b6e59e..b81674d 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1289,16 +1289,20 @@
             err = INVALID_OPERATION;
         } else {
             int32_t isADTS, aacProfile;
+            int32_t sbrMode;
             if (!msg->findInt32("is-adts", &isADTS)) {
                 isADTS = 0;
             }
             if (!msg->findInt32("aac-profile", &aacProfile)) {
                 aacProfile = OMX_AUDIO_AACObjectNull;
             }
+            if (!msg->findInt32("aac-sbr-mode", &sbrMode)) {
+                sbrMode = -1;
+            }
 
             err = setupAACCodec(
                     encoder, numChannels, sampleRate, bitRate, aacProfile,
-                    isADTS != 0);
+                    isADTS != 0, sbrMode);
         }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
         err = setupAMRCodec(encoder, false /* isWAMR */, bitRate);
@@ -1460,7 +1464,7 @@
 
 status_t ACodec::setupAACCodec(
         bool encoder, int32_t numChannels, int32_t sampleRate,
-        int32_t bitRate, int32_t aacProfile, bool isADTS) {
+        int32_t bitRate, int32_t aacProfile, bool isADTS, int32_t sbrMode) {
     if (encoder && isADTS) {
         return -EINVAL;
     }
@@ -1527,6 +1531,32 @@
         profile.nAACERtools = OMX_AUDIO_AACERNone;
         profile.eAACProfile = (OMX_AUDIO_AACPROFILETYPE) aacProfile;
         profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
+        switch (sbrMode) {
+        case 0:
+            // disable sbr
+            profile.nAACtools &= ~OMX_AUDIO_AACToolAndroidSSBR;
+            profile.nAACtools &= ~OMX_AUDIO_AACToolAndroidDSBR;
+            break;
+        case 1:
+            // enable single-rate sbr
+            profile.nAACtools |= OMX_AUDIO_AACToolAndroidSSBR;
+            profile.nAACtools &= ~OMX_AUDIO_AACToolAndroidDSBR;
+            break;
+        case 2:
+            // enable dual-rate sbr
+            profile.nAACtools &= ~OMX_AUDIO_AACToolAndroidSSBR;
+            profile.nAACtools |= OMX_AUDIO_AACToolAndroidDSBR;
+            break;
+        case -1:
+            // enable both modes -> the codec will decide which mode should be used
+            profile.nAACtools |= OMX_AUDIO_AACToolAndroidSSBR;
+            profile.nAACtools |= OMX_AUDIO_AACToolAndroidDSBR;
+            break;
+        default:
+            // unsupported sbr mode
+            return BAD_VALUE;
+        }
+
 
         err = mOMX->setParameter(
                 mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index a67fabe..804f131 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -155,12 +155,12 @@
     }
 
     mStarted = false;
+    mFrameAvailableCondition.signal();
+
     mRecord->stop();
     waitOutstandingEncodingFrames_l();
     releaseQueuedFrames_l();
 
-    mFrameAvailableCondition.signal();
-
     return OK;
 }
 
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 9868ecf..1a80dcc 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -54,7 +54,7 @@
     Puller(const sp<MediaSource> &source);
 
     status_t start(const sp<MetaData> &meta, const sp<AMessage> &notify);
-    void stopAsync();
+    void stop();
 
     void pause();
     void resume();
@@ -139,8 +139,17 @@
     return postSynchronouslyAndReturnError(msg);
 }
 
-void MediaCodecSource::Puller::stopAsync() {
-    ALOGV("puller (%s) stopAsync", mIsAudio ? "audio" : "video");
+void MediaCodecSource::Puller::stop() {
+    // Stop source from caller's thread instead of puller's looper.
+    // mSource->stop() is thread-safe, doing it outside the puller's
+    // looper allows us to at least stop if source gets stuck.
+    // If source gets stuck in read(), the looper would never
+    // be able to process the stop(), which could lead to ANR.
+
+    ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video");
+    mSource->stop();
+    ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video");
+
     (new AMessage(kWhatStop, id()))->post();
 }
 
@@ -194,9 +203,6 @@
 
         case kWhatStop:
         {
-            ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video");
-            mSource->stop();
-            ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video");
             ++mPullGeneration;
 
             handleEOS();
@@ -283,7 +289,21 @@
 
 status_t MediaCodecSource::stop() {
     sp<AMessage> msg = new AMessage(kWhatStop, mReflector->id());
-    return postSynchronouslyAndReturnError(msg);
+    status_t err = postSynchronouslyAndReturnError(msg);
+
+    // mPuller->stop() needs to be done outside MediaCodecSource's looper,
+    // as it contains a synchronous call to stop the underlying MediaSource,
+    // which often waits for all outstanding MediaBuffers to return, but
+    // MediaBuffers are only returned when MediaCodecSource looper gets
+    // to process them.
+
+    if (mPuller != NULL) {
+        ALOGI("puller (%s) stopping", mIsVideo ? "video" : "audio");
+        mPuller->stop();
+        ALOGI("puller (%s) stopped", mIsVideo ? "video" : "audio");
+    }
+
+    return err;
 }
 
 status_t MediaCodecSource::pause() {
@@ -301,10 +321,10 @@
     Mutex::Autolock autolock(mOutputBufferLock);
 
     *buffer = NULL;
-    while (mOutputBufferQueue.size() == 0 && !mEncodedReachedEOS) {
+    while (mOutputBufferQueue.size() == 0 && !mEncoderReachedEOS) {
         mOutputBufferCond.wait(mOutputBufferLock);
     }
-    if (!mEncodedReachedEOS) {
+    if (!mEncoderReachedEOS) {
         *buffer = *mOutputBufferQueue.begin();
         mOutputBufferQueue.erase(mOutputBufferQueue.begin());
         return OK;
@@ -330,9 +350,8 @@
       mStarted(false),
       mStopping(false),
       mDoMoreWorkPending(false),
-      mPullerReachedEOS(false),
       mFirstSampleTimeUs(-1ll),
-      mEncodedReachedEOS(false),
+      mEncoderReachedEOS(false),
       mErrorCode(OK) {
     CHECK(mLooper != NULL);
 
@@ -434,7 +453,7 @@
         return err;
     }
 
-    mEncodedReachedEOS = false;
+    mEncoderReachedEOS = false;
     mErrorCode = OK;
 
     return OK;
@@ -465,10 +484,6 @@
     mEncoderOutputBuffers.clear();
 }
 
-bool MediaCodecSource::reachedEOS() {
-    return mEncodedReachedEOS && ((mPuller == NULL) || mPullerReachedEOS);
-}
-
 status_t MediaCodecSource::postSynchronouslyAndReturnError(
         const sp<AMessage> &msg) {
     sp<AMessage> response;
@@ -486,8 +501,8 @@
 }
 
 void MediaCodecSource::signalEOS(status_t err) {
-    if (!mEncodedReachedEOS) {
-        ALOGI("encoder (%s) reached EOS", mIsVideo ? "video" : "audio");
+    if (!mEncoderReachedEOS) {
+        ALOGV("encoder (%s) reached EOS", mIsVideo ? "video" : "audio");
         {
             Mutex::Autolock autoLock(mOutputBufferLock);
             // release all unread media buffers
@@ -496,16 +511,15 @@
                 (*it)->release();
             }
             mOutputBufferQueue.clear();
-            mEncodedReachedEOS = true;
+            mEncoderReachedEOS = true;
             mErrorCode = err;
             mOutputBufferCond.signal();
         }
 
         releaseEncoder();
     }
-    if (mStopping && reachedEOS()) {
-        ALOGI("MediaCodecSource (%s) fully stopped",
-                mIsVideo ? "video" : "audio");
+    if (mStopping && mEncoderReachedEOS) {
+        ALOGI("encoder (%s) stopped", mIsVideo ? "video" : "audio");
         // posting reply to everyone that's waiting
         List<uint32_t>::iterator it;
         for (it = mStopReplyIDQueue.begin();
@@ -755,7 +769,6 @@
                 kWhatPullerNotify, mReflector->id());
         err = mPuller->start(params, notify);
         if (err != OK) {
-            mPullerReachedEOS = true;
             return err;
         }
     }
@@ -774,9 +787,9 @@
         CHECK(msg->findPointer("accessUnit", (void**)&mbuf));
 
         if (mbuf == NULL) {
-            ALOGI("puller (%s) reached EOS",
+            ALOGV("puller (%s) reached EOS",
                     mIsVideo ? "video" : "audio");
-            mPullerReachedEOS = true;
+            signalEOS();
         }
 
         if (mEncoder == NULL) {
@@ -785,9 +798,8 @@
 
             if (mbuf != NULL) {
                 mbuf->release();
-            } else {
-                signalEOS();
             }
+
             break;
         }
 
@@ -833,14 +845,14 @@
     }
     case kWhatStop:
     {
-        ALOGI("MediaCodecSource (%s) stopping", mIsVideo ? "video" : "audio");
+        ALOGI("encoder (%s) stopping", mIsVideo ? "video" : "audio");
 
         uint32_t replyID;
         CHECK(msg->senderAwaitsResponse(&replyID));
 
-        if (reachedEOS()) {
+        if (mEncoderReachedEOS) {
             // if we already reached EOS, reply and return now
-            ALOGI("MediaCodecSource (%s) already stopped",
+            ALOGI("encoder (%s) already stopped",
                     mIsVideo ? "video" : "audio");
             (new AMessage)->postReply(replyID);
             break;
@@ -860,8 +872,6 @@
         if (mFlags & FLAG_USE_SURFACE_INPUT) {
             mEncoder->signalEndOfInputStream();
         } else {
-            CHECK(mPuller != NULL);
-            mPuller->stopAsync();
             signalEOS();
         }
         break;
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 587e264..5f1d1c6 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -135,6 +135,11 @@
         if (meta->findInt32(kKeyIsADTS, &isADTS)) {
             msg->setInt32("is-adts", true);
         }
+
+        int32_t aacProfile = -1;
+        if (meta->findInt32(kKeyAACAOT, &aacProfile)) {
+            msg->setInt32("aac-profile", aacProfile);
+        }
     }
 
     int32_t maxInputSize;
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
index 6093621..35aa883 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include "SoftAACEncoder2.h"
+#include <OMX_AudioExt.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/hexdump.h>
@@ -44,6 +45,8 @@
       mNumChannels(1),
       mSampleRate(44100),
       mBitRate(0),
+      mSBRMode(-1),
+      mSBRRatio(0),
       mAACProfile(OMX_AUDIO_AACObjectLC),
       mSentCodecSpecificData(false),
       mInputSize(0),
@@ -156,6 +159,41 @@
             aacParams->nSampleRate = mSampleRate;
             aacParams->nFrameLength = 0;
 
+            switch (mSBRMode) {
+            case 1: // sbr on
+                switch (mSBRRatio) {
+                case 0:
+                    // set both OMX AAC tool flags
+                    aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidSSBR;
+                    aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidDSBR;
+                    break;
+                case 1:
+                    // set single-rate SBR active
+                    aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidSSBR;
+                    aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidDSBR;
+                    break;
+                case 2:
+                    // set dual-rate SBR active
+                    aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidSSBR;
+                    aacParams->nAACtools |= OMX_AUDIO_AACToolAndroidDSBR;
+                    break;
+                default:
+                    ALOGE("invalid SBR ratio %d", mSBRRatio);
+                    TRESPASS();
+                }
+                break;
+            case 0:  // sbr off
+            case -1: // sbr undefined
+                aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidSSBR;
+                aacParams->nAACtools &= ~OMX_AUDIO_AACToolAndroidDSBR;
+                break;
+            default:
+                ALOGE("invalid SBR mode %d", mSBRMode);
+                TRESPASS();
+            }
+
+
+
             return OMX_ErrorNone;
         }
 
@@ -243,6 +281,23 @@
                 mAACProfile = aacParams->eAACProfile;
             }
 
+            if (!(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidSSBR)
+                    && !(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidDSBR)) {
+                mSBRMode = 0;
+                mSBRRatio = 0;
+            } else if ((aacParams->nAACtools & OMX_AUDIO_AACToolAndroidSSBR)
+                    && !(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidDSBR)) {
+                mSBRMode = 1;
+                mSBRRatio = 1;
+            } else if (!(aacParams->nAACtools & OMX_AUDIO_AACToolAndroidSSBR)
+                    && (aacParams->nAACtools & OMX_AUDIO_AACToolAndroidDSBR)) {
+                mSBRMode = 1;
+                mSBRRatio = 2;
+            } else {
+                mSBRMode = -1; // codec default sbr mode
+                mSBRRatio = 0;
+            }
+
             if (setAudioParams() != OK) {
                 return OMX_ErrorUndefined;
             }
@@ -305,11 +360,11 @@
 }
 
 status_t SoftAACEncoder2::setAudioParams() {
-    // We call this whenever sample rate, number of channels or bitrate change
+    // We call this whenever sample rate, number of channels, bitrate or SBR mode change
     // in reponse to setParameter calls.
 
-    ALOGV("setAudioParams: %u Hz, %u channels, %u bps",
-         mSampleRate, mNumChannels, mBitRate);
+    ALOGV("setAudioParams: %u Hz, %u channels, %u bps, %i sbr mode, %i sbr ratio",
+         mSampleRate, mNumChannels, mBitRate, mSBRMode, mSBRRatio);
 
     if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_AOT,
             getAOTFromProfile(mAACProfile))) {
@@ -335,6 +390,24 @@
         return UNKNOWN_ERROR;
     }
 
+    if (mSBRMode != -1 && mAACProfile == OMX_AUDIO_AACObjectELD) {
+        if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_MODE, mSBRMode)) {
+            ALOGE("Failed to set AAC encoder parameters");
+            return UNKNOWN_ERROR;
+        }
+    }
+
+    /* SBR ratio parameter configurations:
+       0: Default configuration wherein SBR ratio is configured depending on audio object type by
+          the FDK.
+       1: Downsampled SBR (default for ELD)
+       2: Dualrate SBR (default for HE-AAC)
+     */
+    if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_SBR_RATIO, mSBRRatio)) {
+        ALOGE("Failed to set AAC encoder parameters");
+        return UNKNOWN_ERROR;
+    }
+
     return OK;
 }
 
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
index 2603f4f..bce9c24 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
@@ -53,6 +53,8 @@
     OMX_U32 mNumChannels;
     OMX_U32 mSampleRate;
     OMX_U32 mBitRate;
+    OMX_S32 mSBRMode;
+    OMX_S32 mSBRRatio;
     OMX_U32 mAACProfile;
 
     bool mSentCodecSpecificData;
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 6edca1b..7ac2c0c 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -1797,109 +1797,6 @@
     }
 }
 
-#if 0
-// 2 tracks is also a common case
-// NEVER used in current implementation of process__validate()
-// only use if the 2 tracks have the same output buffer
-void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state,
-                                                            int64_t pts)
-{
-    int i;
-    uint32_t en = state->enabledTracks;
-
-    i = 31 - __builtin_clz(en);
-    const track_t& t0 = state->tracks[i];
-    AudioBufferProvider::Buffer& b0(t0.buffer);
-
-    en &= ~(1<<i);
-    i = 31 - __builtin_clz(en);
-    const track_t& t1 = state->tracks[i];
-    AudioBufferProvider::Buffer& b1(t1.buffer);
-
-    const int16_t *in0;
-    const int16_t vl0 = t0.volume[0];
-    const int16_t vr0 = t0.volume[1];
-    size_t frameCount0 = 0;
-
-    const int16_t *in1;
-    const int16_t vl1 = t1.volume[0];
-    const int16_t vr1 = t1.volume[1];
-    size_t frameCount1 = 0;
-
-    //FIXME: only works if two tracks use same buffer
-    int32_t* out = t0.mainBuffer;
-    size_t numFrames = state->frameCount;
-    const int16_t *buff = NULL;
-
-
-    while (numFrames) {
-
-        if (frameCount0 == 0) {
-            b0.frameCount = numFrames;
-            int64_t outputPTS = calculateOutputPTS(t0, pts,
-                                                   out - t0.mainBuffer);
-            t0.bufferProvider->getNextBuffer(&b0, outputPTS);
-            if (b0.i16 == NULL) {
-                if (buff == NULL) {
-                    buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
-                }
-                in0 = buff;
-                b0.frameCount = numFrames;
-            } else {
-                in0 = b0.i16;
-            }
-            frameCount0 = b0.frameCount;
-        }
-        if (frameCount1 == 0) {
-            b1.frameCount = numFrames;
-            int64_t outputPTS = calculateOutputPTS(t1, pts,
-                                                   out - t0.mainBuffer);
-            t1.bufferProvider->getNextBuffer(&b1, outputPTS);
-            if (b1.i16 == NULL) {
-                if (buff == NULL) {
-                    buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
-                }
-                in1 = buff;
-                b1.frameCount = numFrames;
-            } else {
-                in1 = b1.i16;
-            }
-            frameCount1 = b1.frameCount;
-        }
-
-        size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1;
-
-        numFrames -= outFrames;
-        frameCount0 -= outFrames;
-        frameCount1 -= outFrames;
-
-        do {
-            int32_t l0 = *in0++;
-            int32_t r0 = *in0++;
-            l0 = mul(l0, vl0);
-            r0 = mul(r0, vr0);
-            int32_t l = *in1++;
-            int32_t r = *in1++;
-            l = mulAdd(l, vl1, l0) >> 12;
-            r = mulAdd(r, vr1, r0) >> 12;
-            // clamping...
-            l = clamp16(l);
-            r = clamp16(r);
-            *out++ = (r<<16) | (l & 0xFFFF);
-        } while (--outFrames);
-
-        if (frameCount0 == 0) {
-            t0.bufferProvider->releaseBuffer(&b0);
-        }
-        if (frameCount1 == 0) {
-            t1.bufferProvider->releaseBuffer(&b1);
-        }
-    }
-
-    delete [] buff;
-}
-#endif
-
 int64_t AudioMixer::calculateOutputPTS(const track_t& t, int64_t basePTS,
                                        int outputFrameIndex)
 {
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 5ba377b..3b972bb 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -408,10 +408,6 @@
     static void process__genericResampling(state_t* state, int64_t pts);
     static void process__OneTrack16BitsStereoNoResampling(state_t* state,
                                                           int64_t pts);
-#if 0
-    static void process__TwoTracks16BitsStereoNoResampling(state_t* state,
-                                                           int64_t pts);
-#endif
 
     static int64_t calculateOutputPTS(const track_t& t, int64_t basePTS,
                                       int outputFrameIndex);
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index f3be42d..6512c38 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -30,7 +30,7 @@
     libbinder \
     libmedia \
     libhardware \
-    libhardware_legacy \
+    libhardware_legacy
 
 ifneq ($(USE_LEGACY_AUDIO_POLICY), 1)
 LOCAL_SHARED_LIBRARIES += \
@@ -58,7 +58,8 @@
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
     libutils \
-    liblog
+    liblog \
+    libsoundtrigger
 
 LOCAL_STATIC_LIBRARIES := \
     libmedia_helper
diff --git a/services/audiopolicy/AudioPolicyClientImpl.cpp b/services/audiopolicy/AudioPolicyClientImpl.cpp
index c0019d1..3e090e9 100644
--- a/services/audiopolicy/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/AudioPolicyClientImpl.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "AudioPolicyClientImpl"
 //#define LOG_NDEBUG 0
 
+#include <soundtrigger/SoundTrigger.h>
 #include <utils/Log.h>
 #include "AudioPolicyService.h"
 
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 50ee803..5524463 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -190,6 +190,11 @@
     virtual status_t setAudioPortConfig(const struct audio_port_config *config) = 0;
     virtual void clearAudioPatches(uid_t uid) = 0;
 
+    virtual status_t acquireSoundTriggerSession(audio_session_t *session,
+                                           audio_io_handle_t *ioHandle,
+                                           audio_devices_t *device) = 0;
+
+    virtual status_t releaseSoundTriggerSession(audio_session_t session) = 0;
 };
 
 
diff --git a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
index 75745b3..2c51e25 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
@@ -531,4 +531,24 @@
     return mAudioPolicyManager->setAudioPortConfig(config);
 }
 
+status_t AudioPolicyService::acquireSoundTriggerSession(audio_session_t *session,
+                                       audio_io_handle_t *ioHandle,
+                                       audio_devices_t *device)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+
+    return mAudioPolicyManager->acquireSoundTriggerSession(session, ioHandle, device);
+}
+
+status_t AudioPolicyService::releaseSoundTriggerSession(audio_session_t session)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+
+    return mAudioPolicyManager->releaseSoundTriggerSession(session);
+}
+
 }; // namespace android
diff --git a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
index aa46ace..f20c070 100644
--- a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp
@@ -496,10 +496,21 @@
                                     audio_output_flags_t flags,
                                     const audio_offload_info_t *offloadInfo)
 {
-    //FIXME: temporary to fix build with USE_LEGACY_AUDIO_POLICY
-    audio_stream_type_t stream = AUDIO_STREAM_MUSIC;
+    audio_stream_type_t stream = audio_attributes_to_stream_type(attr);
+
     return getOutput(stream, samplingRate, format, channelMask, flags, offloadInfo);
 }
 
+status_t AudioPolicyService::acquireSoundTriggerSession(audio_session_t *session,
+                                       audio_io_handle_t *ioHandle,
+                                       audio_devices_t *device)
+{
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::releaseSoundTriggerSession(audio_session_t session)
+{
+    return INVALID_OPERATION;
+}
 
 }; // namespace android
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 09595ff..b09300b 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -43,6 +43,7 @@
 #include <hardware/audio.h>
 #include <hardware/audio_effect.h>
 #include <media/AudioParameter.h>
+#include <soundtrigger/SoundTrigger.h>
 #include "AudioPolicyManager.h"
 #include "audio_policy_conf.h"
 
@@ -87,6 +88,7 @@
     STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPDIF),
     STRING_TO_ENUM(AUDIO_DEVICE_OUT_FM),
     STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_LINE),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_AMBIENT),
     STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
     STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
     STRING_TO_ENUM(AUDIO_DEVICE_IN_ALL_SCO),
@@ -709,7 +711,9 @@
             config.sample_rate = mTestSamplingRate;
             config.channel_mask = mTestChannels;
             config.format = mTestFormat;
-            config.offload_info = *offloadInfo;
+            if (offloadInfo != NULL) {
+                config.offload_info = *offloadInfo;
+            }
             status = mpClientInterface->openOutput(0,
                                                   &mTestOutputs[mCurOutput],
                                                   &config,
@@ -784,7 +788,9 @@
         config.sample_rate = samplingRate;
         config.channel_mask = channelMask;
         config.format = format;
-        config.offload_info = *offloadInfo;
+        if (offloadInfo != NULL) {
+            config.offload_info = *offloadInfo;
+        }
         status = mpClientInterface->openOutput(profile->mModule->mHandle,
                                                &output,
                                                &config,
@@ -1115,6 +1121,17 @@
     config.channel_mask = channelMask;
     config.format = format;
     audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+
+    bool isSoundTrigger = false;
+    if (inputSource == AUDIO_SOURCE_HOTWORD) {
+        ssize_t index = mSoundTriggerSessions.indexOfKey(session);
+        if (index >= 0) {
+            input = mSoundTriggerSessions.valueFor(session);
+            isSoundTrigger = true;
+            ALOGV("SoundTrigger capture on session %d input %d", session, input);
+        }
+    }
+
     status_t status = mpClientInterface->openInput(profile->mModule->mHandle,
                                                    &input,
                                                    &config,
@@ -1145,6 +1162,7 @@
     inputDesc->mChannelMask = channelMask;
     inputDesc->mDevice = device;
     inputDesc->mSessions.add(session);
+    inputDesc->mIsSoundTrigger = isSoundTrigger;
 
     addInput(input, inputDesc);
     mpClientInterface->onAudioPortListUpdate();
@@ -1190,6 +1208,9 @@
     }
 
     if (inputDesc->mRefCount == 0) {
+        if (activeInputsCount() == 0) {
+            SoundTrigger::setCaptureState(true);
+        }
         setInputDevice(input, getNewInputDevice(input), true /* force */);
 
         // Automatically enable the remote submix output when input is started.
@@ -1238,6 +1259,10 @@
         }
 
         resetInputDevice(input);
+
+        if (activeInputsCount() == 0) {
+            SoundTrigger::setCaptureState(false);
+        }
     }
     return NO_ERROR;
 }
@@ -2249,6 +2274,31 @@
     }
 }
 
+status_t AudioPolicyManager::acquireSoundTriggerSession(audio_session_t *session,
+                                       audio_io_handle_t *ioHandle,
+                                       audio_devices_t *device)
+{
+    *session = (audio_session_t)mpClientInterface->newAudioUniqueId();
+    *ioHandle = (audio_io_handle_t)mpClientInterface->newAudioUniqueId();
+    *device = getDeviceForInputSource(AUDIO_SOURCE_HOTWORD);
+
+    mSoundTriggerSessions.add(*session, *ioHandle);
+
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::releaseSoundTriggerSession(audio_session_t session)
+{
+    ssize_t index = mSoundTriggerSessions.indexOfKey(session);
+    if (index < 0) {
+        ALOGW("acquireSoundTriggerSession() session %d not registered", session);
+        return BAD_VALUE;
+    }
+
+    mSoundTriggerSessions.removeItem(session);
+    return NO_ERROR;
+}
+
 status_t AudioPolicyManager::addAudioPatch(audio_patch_handle_t handle,
                                            const sp<AudioPatch>& patch)
 {
@@ -3657,6 +3707,8 @@
                 device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
                 if (device) break;
             }
+            device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_LINE;
+            if (device) break;
             device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER;
             if (device) break;
             device = mDefaultOutputDevice->mDeviceType;
@@ -3713,6 +3765,9 @@
         if (device2 == AUDIO_DEVICE_NONE) {
             device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
         }
+        if ((device2 == AUDIO_DEVICE_NONE)) {
+            device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_LINE;
+        }
         if (device2 == AUDIO_DEVICE_NONE) {
             device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADSET;
         }
@@ -4009,7 +4064,8 @@
             inputDesc->toAudioPortConfig(&patch.sinks[0]);
             // AUDIO_SOURCE_HOTWORD is for internal use only:
             // handled as AUDIO_SOURCE_VOICE_RECOGNITION by the audio HAL
-            if (patch.sinks[0].ext.mix.usecase.source == AUDIO_SOURCE_HOTWORD) {
+            if (patch.sinks[0].ext.mix.usecase.source == AUDIO_SOURCE_HOTWORD &&
+                    !inputDesc->mIsSoundTrigger) {
                 patch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_VOICE_RECOGNITION;
             }
             patch.num_sinks = 1;
@@ -4194,6 +4250,18 @@
     return 0;
 }
 
+uint32_t AudioPolicyManager::activeInputsCount() const
+{
+    uint32_t count = 0;
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        const sp<AudioInputDescriptor>  desc = mInputs.valueAt(i);
+        if (desc->mRefCount > 0) {
+            return count++;
+        }
+    }
+    return count;
+}
+
 
 audio_devices_t AudioPolicyManager::getDeviceForVolume(audio_devices_t device)
 {
@@ -4233,10 +4301,13 @@
         case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
         case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
             return DEVICE_CATEGORY_HEADSET;
+        case AUDIO_DEVICE_OUT_LINE:
+        case AUDIO_DEVICE_OUT_AUX_DIGITAL:
+        /*USB?  Remote submix?*/
+            return DEVICE_CATEGORY_EXT_MEDIA;
         case AUDIO_DEVICE_OUT_SPEAKER:
         case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
         case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
-        case AUDIO_DEVICE_OUT_AUX_DIGITAL:
         case AUDIO_DEVICE_OUT_USB_ACCESSORY:
         case AUDIO_DEVICE_OUT_USB_DEVICE:
         case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
@@ -4303,6 +4374,11 @@
 };
 
 const AudioPolicyManager::VolumeCurvePoint
+    AudioPolicyManager::sExtMediaSystemVolumeCurve[AudioPolicyManager::VOLCNT] = {
+    {1, -58.0f}, {20, -40.0f}, {60, -21.0f}, {100, -10.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
     AudioPolicyManager::sSpeakerMediaVolumeCurve[AudioPolicyManager::VOLCNT] = {
     {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f}
 };
@@ -4358,52 +4434,62 @@
     { // AUDIO_STREAM_VOICE_CALL
         sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
         sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
-        sDefaultVoiceVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+        sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+        sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
     },
     { // AUDIO_STREAM_SYSTEM
         sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
         sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
-        sDefaultSystemVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+        sDefaultSystemVolumeCurve,  // DEVICE_CATEGORY_EARPIECE
+        sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
     },
     { // AUDIO_STREAM_RING
         sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
         sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
-        sDefaultVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+        sDefaultVolumeCurve,  // DEVICE_CATEGORY_EARPIECE
+        sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
     },
     { // AUDIO_STREAM_MUSIC
         sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
         sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
-        sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+        sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+        sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
     },
     { // AUDIO_STREAM_ALARM
         sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
         sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
-        sDefaultVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+        sDefaultVolumeCurve,  // DEVICE_CATEGORY_EARPIECE
+        sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
     },
     { // AUDIO_STREAM_NOTIFICATION
         sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
         sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
-        sDefaultVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+        sDefaultVolumeCurve,  // DEVICE_CATEGORY_EARPIECE
+        sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
     },
     { // AUDIO_STREAM_BLUETOOTH_SCO
         sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
         sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
-        sDefaultVoiceVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+        sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+        sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
     },
     { // AUDIO_STREAM_ENFORCED_AUDIBLE
         sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
         sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
-        sDefaultSystemVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+        sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+        sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
     },
     {  // AUDIO_STREAM_DTMF
         sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
         sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
-        sDefaultSystemVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+        sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+        sExtMediaSystemVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
     },
     { // AUDIO_STREAM_TTS
         sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
         sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
-        sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+        sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE
+        sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EXT_MEDIA
     },
 };
 
@@ -4879,7 +4965,7 @@
 AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
     : mId(0), mIoHandle(0),
       mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0), mRefCount(0),
-      mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile)
+      mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false)
 {
     if (profile != NULL) {
         mAudioPort = profile;
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index e28a362..47235f7 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -172,6 +172,12 @@
         virtual status_t setAudioPortConfig(const struct audio_port_config *config);
         virtual void clearAudioPatches(uid_t uid);
 
+        virtual status_t acquireSoundTriggerSession(audio_session_t *session,
+                                               audio_io_handle_t *ioHandle,
+                                               audio_devices_t *device);
+
+        virtual status_t releaseSoundTriggerSession(audio_session_t session);
+
 protected:
 
         enum routing_strategy {
@@ -202,6 +208,7 @@
             DEVICE_CATEGORY_HEADSET,
             DEVICE_CATEGORY_SPEAKER,
             DEVICE_CATEGORY_EARPIECE,
+            DEVICE_CATEGORY_EXT_MEDIA,
             DEVICE_CATEGORY_CNT
         };
 
@@ -408,6 +415,8 @@
         static const VolumeCurvePoint sDefaultVolumeCurve[AudioPolicyManager::VOLCNT];
         // default volume curve for media strategy
         static const VolumeCurvePoint sDefaultMediaVolumeCurve[AudioPolicyManager::VOLCNT];
+        // volume curve for non-media audio on ext media outputs (HDMI, Line, etc)
+        static const VolumeCurvePoint sExtMediaSystemVolumeCurve[AudioPolicyManager::VOLCNT];
         // volume curve for media strategy on speakers
         static const VolumeCurvePoint sSpeakerMediaVolumeCurve[AudioPolicyManager::VOLCNT];
         static const VolumeCurvePoint sSpeakerMediaVolumeCurveDrc[AudioPolicyManager::VOLCNT];
@@ -477,15 +486,18 @@
 
             status_t    dump(int fd);
 
-            audio_port_handle_t mId;
-            audio_io_handle_t mIoHandle;              // input handle
-            audio_devices_t mDevice;                    // current device this input is routed to
-            audio_patch_handle_t mPatchHandle;
-            uint32_t mRefCount;                         // number of AudioRecord clients using this output
-            uint32_t mOpenRefCount;
-            audio_source_t mInputSource;                // input source selected by application (mediarecorder.h)
-            const sp<IOProfile> mProfile;                  // I/O profile this output derives from
-            SortedVector<audio_session_t> mSessions;  // audio sessions attached to this input
+            audio_port_handle_t           mId;
+            audio_io_handle_t             mIoHandle;       // input handle
+            audio_devices_t               mDevice;         // current device this input is routed to
+            audio_patch_handle_t          mPatchHandle;
+            uint32_t                      mRefCount;       // number of AudioRecord clients using
+                                                           // this input
+            uint32_t                      mOpenRefCount;
+            audio_source_t                mInputSource;    // input source selected by application
+                                                           //(mediarecorder.h)
+            const sp<IOProfile>           mProfile;        // I/O profile this output derives from
+            SortedVector<audio_session_t> mSessions;       // audio sessions attached to this input
+            bool                          mIsSoundTrigger; // used by a soundtrigger capture
 
             virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
                                    const struct audio_port_config *srcConfig = NULL) const;
@@ -569,6 +581,8 @@
         //    ignoreVirtualInputs is true.
         audio_io_handle_t getActiveInput(bool ignoreVirtualInputs = true);
 
+        uint32_t activeInputsCount() const;
+
         // initialize volume curves for each strategy and device category
         void initializeVolumeCurves();
 
@@ -769,6 +783,8 @@
 
         DefaultKeyedVector<audio_patch_handle_t, sp<AudioPatch> > mAudioPatches;
 
+        DefaultKeyedVector<audio_session_t, audio_io_handle_t> mSoundTriggerSessions;
+
 #ifdef AUDIO_POLICY_TEST
         Mutex   mLock;
         Condition mWaitWorkCV;
diff --git a/services/audiopolicy/AudioPolicyService.h b/services/audiopolicy/AudioPolicyService.h
index 97236e3..0044e7a 100644
--- a/services/audiopolicy/AudioPolicyService.h
+++ b/services/audiopolicy/AudioPolicyService.h
@@ -168,6 +168,12 @@
 
     virtual void registerClient(const sp<IAudioPolicyServiceClient>& client);
 
+    virtual status_t acquireSoundTriggerSession(audio_session_t *session,
+                                           audio_io_handle_t *ioHandle,
+                                           audio_devices_t *device);
+
+    virtual status_t releaseSoundTriggerSession(audio_session_t session);
+
             status_t doStopOutput(audio_io_handle_t output,
                                   audio_stream_type_t stream,
                                   int session = 0);
diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk
index 51eb845..572ae56 100644
--- a/services/soundtrigger/Android.mk
+++ b/services/soundtrigger/Android.mk
@@ -31,7 +31,8 @@
     libbinder \
     libcutils \
     libhardware \
-    libsoundtrigger
+    libsoundtrigger \
+    libmedia
 
 LOCAL_STATIC_LIBRARIES := \
     libserviceutility
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 3654136..2502e0d 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -25,12 +25,13 @@
 #include <system/sound_trigger.h>
 #include <cutils/atomic.h>
 #include <cutils/properties.h>
+#include <hardware/hardware.h>
+#include <media/AudioSystem.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <binder/IServiceManager.h>
 #include <binder/MemoryBase.h>
 #include <binder/MemoryHeapBase.h>
-#include <hardware/hardware.h>
 #include <hardware/sound_trigger.h>
 #include <ServiceUtilities.h>
 #include "SoundTriggerHwService.h"
@@ -45,7 +46,9 @@
 
 SoundTriggerHwService::SoundTriggerHwService()
     : BnSoundTriggerHwService(),
-      mNextUniqueId(1)
+      mNextUniqueId(1),
+      mMemoryDealer(new MemoryDealer(1024 * 1024, "SoundTriggerHwService")),
+      mCaptureState(false)
 {
 }
 
@@ -143,15 +146,31 @@
     client->asBinder()->linkToDeath(module);
     moduleInterface = module;
 
+    module->setCaptureState_l(mCaptureState);
+
     return NO_ERROR;
 }
 
-void SoundTriggerHwService::detachModule(sp<Module> module) {
+status_t SoundTriggerHwService::setCaptureState(bool active)
+{
+    ALOGV("setCaptureState %d", active);
+    AutoMutex lock(mServiceLock);
+    mCaptureState = active;
+    for (size_t i = 0; i < mModules.size(); i++) {
+        mModules.valueAt(i)->setCaptureState_l(active);
+    }
+    return NO_ERROR;
+}
+
+
+void SoundTriggerHwService::detachModule(sp<Module> module)
+{
     ALOGV("detachModule");
     AutoMutex lock(mServiceLock);
     module->clearClient();
 }
 
+
 static const int kDumpLockRetries = 50;
 static const int kDumpLockSleep = 60000;
 
@@ -200,18 +219,175 @@
     if (module == NULL) {
         return;
     }
-    module->sendRecognitionEvent(event);
+    sp<SoundTriggerHwService> service = module->service().promote();
+    if (service == 0) {
+        return;
+    }
+
+    service->sendRecognitionEvent(event, module);
+}
+
+sp<IMemory> SoundTriggerHwService::prepareRecognitionEvent_l(
+                                                    struct sound_trigger_recognition_event *event)
+{
+    sp<IMemory> eventMemory;
+
+    //sanitize event
+    switch (event->type) {
+    case SOUND_MODEL_TYPE_KEYPHRASE:
+        ALOGW_IF(event->data_size != 0 && event->data_offset !=
+                    sizeof(struct sound_trigger_phrase_recognition_event),
+                    "prepareRecognitionEvent_l(): invalid data offset %u for keyphrase event type",
+                    event->data_offset);
+        event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
+        break;
+    case SOUND_MODEL_TYPE_UNKNOWN:
+        ALOGW_IF(event->data_size != 0 && event->data_offset !=
+                    sizeof(struct sound_trigger_recognition_event),
+                    "prepareRecognitionEvent_l(): invalid data offset %u for unknown event type",
+                    event->data_offset);
+        event->data_offset = sizeof(struct sound_trigger_recognition_event);
+        break;
+    default:
+            return eventMemory;
+    }
+
+    size_t size = event->data_offset + event->data_size;
+    eventMemory = mMemoryDealer->allocate(size);
+    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+        eventMemory.clear();
+        return eventMemory;
+    }
+    memcpy(eventMemory->pointer(), event, size);
+
+    return eventMemory;
+}
+
+void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognition_event *event,
+                                                 Module *module)
+ {
+     AutoMutex lock(mServiceLock);
+     if (module == NULL) {
+         return;
+     }
+     sp<IMemory> eventMemory = prepareRecognitionEvent_l(event);
+     if (eventMemory == 0) {
+         return;
+     }
+     sp<Module> strongModule;
+     for (size_t i = 0; i < mModules.size(); i++) {
+         if (mModules.valueAt(i).get() == module) {
+             strongModule = mModules.valueAt(i);
+             break;
+         }
+     }
+     if (strongModule == 0) {
+         return;
+     }
+
+     sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_RECOGNITION,
+                                                  eventMemory, strongModule));
+}
+
+// static
+void SoundTriggerHwService::soundModelCallback(struct sound_trigger_model_event *event,
+                                               void *cookie)
+{
+    Module *module = (Module *)cookie;
+    if (module == NULL) {
+        return;
+    }
+    sp<SoundTriggerHwService> service = module->service().promote();
+    if (service == 0) {
+        return;
+    }
+
+    service->sendSoundModelEvent(event, module);
+}
+
+sp<IMemory> SoundTriggerHwService::prepareSoundModelEvent_l(struct sound_trigger_model_event *event)
+{
+    sp<IMemory> eventMemory;
+
+    size_t size = event->data_offset + event->data_size;
+    eventMemory = mMemoryDealer->allocate(size);
+    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+        eventMemory.clear();
+        return eventMemory;
+    }
+    memcpy(eventMemory->pointer(), event, size);
+
+    return eventMemory;
+}
+
+void SoundTriggerHwService::sendSoundModelEvent(struct sound_trigger_model_event *event,
+                                                Module *module)
+{
+    AutoMutex lock(mServiceLock);
+    sp<IMemory> eventMemory = prepareSoundModelEvent_l(event);
+    if (eventMemory == 0) {
+        return;
+    }
+    sp<Module> strongModule;
+    for (size_t i = 0; i < mModules.size(); i++) {
+        if (mModules.valueAt(i).get() == module) {
+            strongModule = mModules.valueAt(i);
+            break;
+        }
+    }
+    if (strongModule == 0) {
+        return;
+    }
+    sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_SOUNDMODEL,
+                                                 eventMemory, strongModule));
 }
 
 
-void SoundTriggerHwService::sendRecognitionEvent(const sp<RecognitionEvent>& event)
+sp<IMemory> SoundTriggerHwService::prepareServiceStateEvent_l(sound_trigger_service_state_t state)
 {
-    mCallbackThread->sendRecognitionEvent(event);
+    sp<IMemory> eventMemory;
+
+    size_t size = sizeof(sound_trigger_service_state_t);
+    eventMemory = mMemoryDealer->allocate(size);
+    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+        eventMemory.clear();
+        return eventMemory;
+    }
+    *((sound_trigger_service_state_t *)eventMemory->pointer()) = state;
+    return eventMemory;
 }
 
-void SoundTriggerHwService::onRecognitionEvent(const sp<RecognitionEvent>& event)
+// call with mServiceLock held
+void SoundTriggerHwService::sendServiceStateEvent_l(sound_trigger_service_state_t state,
+                                                  Module *module)
 {
-    ALOGV("onRecognitionEvent");
+    sp<IMemory> eventMemory = prepareServiceStateEvent_l(state);
+    if (eventMemory == 0) {
+        return;
+    }
+    sp<Module> strongModule;
+    for (size_t i = 0; i < mModules.size(); i++) {
+        if (mModules.valueAt(i).get() == module) {
+            strongModule = mModules.valueAt(i);
+            break;
+        }
+    }
+    if (strongModule == 0) {
+        return;
+    }
+    sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE,
+                                                 eventMemory, strongModule));
+}
+
+// call with mServiceLock held
+void SoundTriggerHwService::sendCallbackEvent_l(const sp<CallbackEvent>& event)
+{
+    mCallbackThread->sendCallbackEvent(event);
+}
+
+void SoundTriggerHwService::onCallbackEvent(const sp<CallbackEvent>& event)
+{
+    ALOGV("onCallbackEvent");
     sp<Module> module;
     {
         AutoMutex lock(mServiceLock);
@@ -220,15 +396,12 @@
             return;
         }
     }
-    module->onRecognitionEvent(event->mEventMemory);
-}
-
-// static
-void SoundTriggerHwService::soundModelCallback(struct sound_trigger_model_event *event __unused,
-                                               void *cookie)
-{
-    Module *module = (Module *)cookie;
-
+    module->onCallbackEvent(event);
+    {
+        AutoMutex lock(mServiceLock);
+        // clear now to execute with mServiceLock locked
+        event->mMemory.clear();
+    }
 }
 
 #undef LOG_TAG
@@ -241,7 +414,10 @@
 
 SoundTriggerHwService::CallbackThread::~CallbackThread()
 {
-    mEventQueue.clear();
+    while (!mEventQueue.isEmpty()) {
+        mEventQueue[0]->mMemory.clear();
+        mEventQueue.removeAt(0);
+    }
 }
 
 void SoundTriggerHwService::CallbackThread::onFirstRef()
@@ -252,7 +428,7 @@
 bool SoundTriggerHwService::CallbackThread::threadLoop()
 {
     while (!exitPending()) {
-        sp<RecognitionEvent> event;
+        sp<CallbackEvent> event;
         sp<SoundTriggerHwService> service;
         {
             Mutex::Autolock _l(mCallbackLock);
@@ -269,7 +445,7 @@
             service = mService.promote();
         }
         if (service != 0) {
-            service->onRecognitionEvent(event);
+            service->onCallbackEvent(event);
         }
     }
     return false;
@@ -282,25 +458,25 @@
     mCallbackCond.broadcast();
 }
 
-void SoundTriggerHwService::CallbackThread::sendRecognitionEvent(
-                        const sp<SoundTriggerHwService::RecognitionEvent>& event)
+void SoundTriggerHwService::CallbackThread::sendCallbackEvent(
+                        const sp<SoundTriggerHwService::CallbackEvent>& event)
 {
     AutoMutex lock(mCallbackLock);
     mEventQueue.add(event);
     mCallbackCond.signal();
 }
 
-SoundTriggerHwService::RecognitionEvent::RecognitionEvent(
-                                            sp<IMemory> eventMemory,
-                                            wp<Module> module)
-    : mEventMemory(eventMemory), mModule(module)
+SoundTriggerHwService::CallbackEvent::CallbackEvent(event_type type, sp<IMemory> memory,
+                                                    wp<Module> module)
+    : mType(type), mMemory(memory), mModule(module)
 {
 }
 
-SoundTriggerHwService::RecognitionEvent::~RecognitionEvent()
+SoundTriggerHwService::CallbackEvent::~CallbackEvent()
 {
 }
 
+
 #undef LOG_TAG
 #define LOG_TAG "SoundTriggerHwService::Module"
 
@@ -309,7 +485,7 @@
                                       sound_trigger_module_descriptor descriptor,
                                       const sp<ISoundTriggerClient>& client)
  : mService(service), mHwDevice(hwDevice), mDescriptor(descriptor),
-   mClient(client)
+   mClient(client), mServiceState(SOUND_TRIGGER_STATE_NO_INIT)
 {
 }
 
@@ -328,7 +504,6 @@
             ALOGV("detach() unloading model %d", model->mHandle);
             if (model->mState == Model::STATE_ACTIVE) {
                 mHwDevice->stop_recognition(mHwDevice, model->mHandle);
-                model->deallocateMemory();
             }
             mHwDevice->unload_sound_model(mHwDevice, model->mHandle);
         }
@@ -365,9 +540,20 @@
                                                   SoundTriggerHwService::soundModelCallback,
                                                   this,
                                                   handle);
-    if (status == NO_ERROR) {
-        mModels.replaceValueFor(*handle, new Model(*handle));
+    if (status != NO_ERROR) {
+        return status;
     }
+    audio_session_t session;
+    audio_io_handle_t ioHandle;
+    audio_devices_t device;
+
+    status = AudioSystem::acquireSoundTriggerSession(&session, &ioHandle, &device);
+    if (status != NO_ERROR) {
+        return status;
+    }
+
+    sp<Model> model = new Model(*handle, session, ioHandle, device, sound_model->type);
+    mModels.replaceValueFor(*handle, model);
 
     return status;
 }
@@ -388,8 +574,8 @@
     mModels.removeItem(handle);
     if (model->mState == Model::STATE_ACTIVE) {
         mHwDevice->stop_recognition(mHwDevice, model->mHandle);
-        model->deallocateMemory();
     }
+    AudioSystem::releaseSoundTriggerSession(model->mCaptureSession);
     return mHwDevice->unload_sound_model(mHwDevice, handle);
 }
 
@@ -407,6 +593,9 @@
 
     }
     AutoMutex lock(mLock);
+    if (mServiceState == SOUND_TRIGGER_STATE_DISABLED) {
+        return INVALID_OPERATION;
+    }
     sp<Model> model = getModel(handle);
     if (model == 0) {
         return BAD_VALUE;
@@ -419,17 +608,23 @@
     if (model->mState == Model::STATE_ACTIVE) {
         return INVALID_OPERATION;
     }
-    model->mState = Model::STATE_ACTIVE;
 
     struct sound_trigger_recognition_config *config =
             (struct sound_trigger_recognition_config *)dataMemory->pointer();
 
     //TODO: get capture handle and device from audio policy service
-    config->capture_handle = AUDIO_IO_HANDLE_NONE;
-    config->capture_device = AUDIO_DEVICE_NONE;
-    return mHwDevice->start_recognition(mHwDevice, handle, config,
+    config->capture_handle = model->mCaptureIOHandle;
+    config->capture_device = model->mCaptureDevice;
+    status_t status = mHwDevice->start_recognition(mHwDevice, handle, config,
                                         SoundTriggerHwService::recognitionCallback,
                                         this);
+
+    if (status == NO_ERROR) {
+        model->mState = Model::STATE_ACTIVE;
+        model->mConfig = *config;
+    }
+
+    return status;
 }
 
 status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle)
@@ -449,93 +644,62 @@
         return INVALID_OPERATION;
     }
     mHwDevice->stop_recognition(mHwDevice, handle);
-    model->deallocateMemory();
     model->mState = Model::STATE_IDLE;
     return NO_ERROR;
 }
 
-void SoundTriggerHwService::Module::sendRecognitionEvent(
-                                                    struct sound_trigger_recognition_event *event)
+
+void SoundTriggerHwService::Module::onCallbackEvent(const sp<CallbackEvent>& event)
 {
-    sp<SoundTriggerHwService> service;
-    sp<IMemory> eventMemory;
-    ALOGV("sendRecognitionEvent for model %d", event->model);
-    {
-        AutoMutex lock(mLock);
-        sp<Model> model = getModel(event->model);
-        if (model == 0) {
-            return;
-        }
-        if (model->mState != Model::STATE_ACTIVE) {
-            ALOGV("sendRecognitionEvent model->mState %d != Model::STATE_ACTIVE", model->mState);
-            return;
-        }
-        if (mClient == 0) {
-            return;
-        }
-        service = mService.promote();
-        if (service == 0) {
-            return;
-        }
-
-        //sanitize event
-        switch (event->type) {
-        case SOUND_MODEL_TYPE_KEYPHRASE:
-            ALOGW_IF(event->data_offset !=
-                        sizeof(struct sound_trigger_phrase_recognition_event),
-                        "sendRecognitionEvent(): invalid data offset %u for keyphrase event type",
-                        event->data_offset);
-            event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
-            break;
-        case SOUND_MODEL_TYPE_UNKNOWN:
-            ALOGW_IF(event->data_offset !=
-                        sizeof(struct sound_trigger_recognition_event),
-                        "sendRecognitionEvent(): invalid data offset %u for unknown event type",
-                        event->data_offset);
-            event->data_offset = sizeof(struct sound_trigger_recognition_event);
-            break;
-        default:
-                return;
-        }
-
-        size_t size = event->data_offset + event->data_size;
-        eventMemory = model->allocateMemory(size);
-        if (eventMemory == 0 || eventMemory->pointer() == NULL) {
-            return;
-        }
-        memcpy(eventMemory->pointer(), event, size);
-    }
-    service->sendRecognitionEvent(new RecognitionEvent(eventMemory, this));
-}
-
-void SoundTriggerHwService::Module::onRecognitionEvent(sp<IMemory> eventMemory)
-{
-    ALOGV("Module::onRecognitionEvent");
+    ALOGV("onCallbackEvent type %d", event->mType);
 
     AutoMutex lock(mLock);
+    sp<IMemory> eventMemory = event->mMemory;
 
     if (eventMemory == 0 || eventMemory->pointer() == NULL) {
         return;
     }
-    struct sound_trigger_recognition_event *event =
-            (struct sound_trigger_recognition_event *)eventMemory->pointer();
-
-    sp<Model> model = getModel(event->model);
-    if (model == 0) {
-        ALOGI("%s model == 0", __func__);
-        return;
-    }
-    if (model->mState != Model::STATE_ACTIVE) {
-        ALOGV("onRecognitionEvent model->mState %d != Model::STATE_ACTIVE", model->mState);
-        return;
-    }
     if (mClient == 0) {
         ALOGI("%s mClient == 0", __func__);
         return;
     }
-    mClient->onRecognitionEvent(eventMemory);
-    model->mState = Model::STATE_IDLE;
-    model->deallocateMemory();
+
+    switch (event->mType) {
+    case CallbackEvent::TYPE_RECOGNITION: {
+        struct sound_trigger_recognition_event *recognitionEvent =
+                (struct sound_trigger_recognition_event *)eventMemory->pointer();
+
+        sp<Model> model = getModel(recognitionEvent->model);
+        if (model == 0) {
+            ALOGW("%s model == 0", __func__);
+            return;
+        }
+        if (model->mState != Model::STATE_ACTIVE) {
+            ALOGV("onCallbackEvent model->mState %d != Model::STATE_ACTIVE", model->mState);
+            return;
+        }
+
+        recognitionEvent->capture_session = model->mCaptureSession;
+        mClient->onRecognitionEvent(eventMemory);
+        model->mState = Model::STATE_IDLE;
+    } break;
+    case CallbackEvent::TYPE_SOUNDMODEL: {
+        struct sound_trigger_model_event *soundmodelEvent =
+                (struct sound_trigger_model_event *)eventMemory->pointer();
+
+        sp<Model> model = getModel(soundmodelEvent->model);
+        if (model == 0) {
+            ALOGW("%s model == 0", __func__);
+            return;
+        }
+        mClient->onSoundModelEvent(eventMemory);
+    } break;
+    case CallbackEvent::TYPE_SERVICE_STATE: {
+        mClient->onServiceStateChange(eventMemory);
+    } break;
+    default:
+        LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType);
+    }
 }
 
 sp<SoundTriggerHwService::Model> SoundTriggerHwService::Module::getModel(
@@ -555,30 +719,80 @@
     detach();
 }
 
-
-SoundTriggerHwService::Model::Model(sound_model_handle_t handle) :
-    mHandle(handle), mState(STATE_IDLE), mInputHandle(AUDIO_IO_HANDLE_NONE),
-    mCaptureSession(AUDIO_SESSION_ALLOCATE),
-    mMemoryDealer(new MemoryDealer(sizeof(struct sound_trigger_recognition_event),
-                                   "SoundTriggerHwService::Event"))
+// Called with mServiceLock held
+void SoundTriggerHwService::Module::setCaptureState_l(bool active)
 {
+    ALOGV("Module::setCaptureState_l %d", active);
+    sp<SoundTriggerHwService> service;
+    sound_trigger_service_state_t state;
 
-}
+    Vector< sp<IMemory> > events;
+    {
+        AutoMutex lock(mLock);
+        state = (active && !mDescriptor.properties.concurrent_capture) ?
+                                        SOUND_TRIGGER_STATE_DISABLED : SOUND_TRIGGER_STATE_ENABLED;
 
+        if (state == mServiceState) {
+            return;
+        }
 
-sp<IMemory> SoundTriggerHwService::Model::allocateMemory(size_t size)
-{
-    sp<IMemory> memory;
-    if (mMemoryDealer->getMemoryHeap()->getSize() < size) {
-        mMemoryDealer = new MemoryDealer(size, "SoundTriggerHwService::Event");
+        mServiceState = state;
+
+        service = mService.promote();
+        if (service == 0) {
+            return;
+        }
+
+        if (state == SOUND_TRIGGER_STATE_ENABLED) {
+            goto exit;
+        }
+
+        for (size_t i = 0; i < mModels.size(); i++) {
+            sp<Model> model = mModels.valueAt(i);
+            if (model->mState == Model::STATE_ACTIVE) {
+                mHwDevice->stop_recognition(mHwDevice, model->mHandle);
+                // keep model in ACTIVE state so that event is processed by onCallbackEvent()
+                struct sound_trigger_phrase_recognition_event phraseEvent;
+                switch (model->mType) {
+                case SOUND_MODEL_TYPE_KEYPHRASE:
+                    phraseEvent.num_phrases = model->mConfig.num_phrases;
+                    for (size_t i = 0; i < phraseEvent.num_phrases; i++) {
+                        phraseEvent.phrase_extras[i] = model->mConfig.phrases[i];
+                    }
+                    break;
+                case SOUND_MODEL_TYPE_UNKNOWN:
+                default:
+                    break;
+                }
+                phraseEvent.common.status = RECOGNITION_STATUS_ABORT;
+                phraseEvent.common.type = model->mType;
+                phraseEvent.common.model = model->mHandle;
+                phraseEvent.common.data_size = 0;
+                sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&phraseEvent.common);
+                if (eventMemory != 0) {
+                    events.add(eventMemory);
+                }
+            }
+        }
     }
-    memory = mMemoryDealer->allocate(size);
-    return memory;
+
+    for (size_t i = 0; i < events.size(); i++) {
+        service->sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_RECOGNITION, events[i],
+                                                     this));
+    }
+
+exit:
+    service->sendServiceStateEvent_l(state, this);
 }
 
-void SoundTriggerHwService::Model::deallocateMemory()
+
+SoundTriggerHwService::Model::Model(sound_model_handle_t handle, audio_session_t session,
+                                    audio_io_handle_t ioHandle, audio_devices_t device,
+                                    sound_trigger_sound_model_type_t type) :
+    mHandle(handle), mState(STATE_IDLE), mCaptureSession(session),
+    mCaptureIOHandle(ioHandle), mCaptureDevice(device), mType(type)
 {
-    mMemoryDealer->deallocate(0);
+
 }
 
 status_t SoundTriggerHwService::Module::dump(int fd __unused,
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
index 377f2a1..d05dacd 100644
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -53,6 +53,8 @@
                             const sp<ISoundTriggerClient>& client,
                             sp<ISoundTrigger>& module);
 
+    virtual status_t setCaptureState(bool active);
+
     virtual status_t    onTransact(uint32_t code, const Parcel& data,
                                    Parcel* reply, uint32_t flags);
 
@@ -66,17 +68,33 @@
             STATE_ACTIVE
         };
 
-        Model(sound_model_handle_t handle);
+        Model(sound_model_handle_t handle, audio_session_t session, audio_io_handle_t ioHandle,
+              audio_devices_t device, sound_trigger_sound_model_type_t type);
         ~Model() {}
 
-        sp<IMemory> allocateMemory(size_t size);
-        void deallocateMemory();
-
         sound_model_handle_t    mHandle;
         int                     mState;
-        audio_io_handle_t       mInputHandle;
         audio_session_t         mCaptureSession;
-        sp<MemoryDealer>        mMemoryDealer;
+        audio_io_handle_t       mCaptureIOHandle;
+        audio_devices_t         mCaptureDevice;
+        sound_trigger_sound_model_type_t mType;
+        struct sound_trigger_recognition_config mConfig;
+    };
+
+    class CallbackEvent : public RefBase {
+    public:
+        typedef enum {
+            TYPE_RECOGNITION,
+            TYPE_SOUNDMODEL,
+            TYPE_SERVICE_STATE,
+        } event_type;
+        CallbackEvent(event_type type, sp<IMemory> memory, wp<Module> module);
+
+        virtual             ~CallbackEvent();
+
+        event_type mType;
+        sp<IMemory> mMemory;
+        wp<Module> mModule;
     };
 
     class Module : public virtual RefBase,
@@ -109,36 +127,29 @@
        struct sound_trigger_module_descriptor descriptor() { return mDescriptor; }
        void setClient(sp<ISoundTriggerClient> client) { mClient = client; }
        void clearClient() { mClient.clear(); }
-       sp<ISoundTriggerClient> client() { return mClient; }
+       sp<ISoundTriggerClient> client() const { return mClient; }
+       wp<SoundTriggerHwService> service() const { return mService; }
 
-       void sendRecognitionEvent(struct sound_trigger_recognition_event *event);
-       void onRecognitionEvent(sp<IMemory> eventMemory);
+       void onCallbackEvent(const sp<CallbackEvent>& event);
 
        sp<Model> getModel(sound_model_handle_t handle);
 
+       void setCaptureState_l(bool active);
+
        // IBinder::DeathRecipient implementation
        virtual void        binderDied(const wp<IBinder> &who);
 
     private:
+
         Mutex                                  mLock;
         wp<SoundTriggerHwService>              mService;
         struct sound_trigger_hw_device*        mHwDevice;
         struct sound_trigger_module_descriptor mDescriptor;
         sp<ISoundTriggerClient>                mClient;
         DefaultKeyedVector< sound_model_handle_t, sp<Model> >     mModels;
+        sound_trigger_service_state_t          mServiceState;
     }; // class Module
 
-    class RecognitionEvent : public RefBase {
-    public:
-
-        RecognitionEvent(sp<IMemory> eventMemory, wp<Module> module);
-
-        virtual             ~RecognitionEvent();
-
-        sp<IMemory> mEventMemory;
-        wp<Module> mModule;
-    };
-
     class CallbackThread : public Thread {
     public:
 
@@ -153,22 +164,30 @@
         virtual void        onFirstRef();
 
                 void        exit();
-                void        sendRecognitionEvent(const sp<RecognitionEvent>& event);
+                void        sendCallbackEvent(const sp<CallbackEvent>& event);
 
     private:
         wp<SoundTriggerHwService>   mService;
         Condition                   mCallbackCond;
         Mutex                       mCallbackLock;
-        Vector< sp<RecognitionEvent> > mEventQueue;
+        Vector< sp<CallbackEvent> > mEventQueue;
     };
 
-    void detachModule(sp<Module> module);
+           void detachModule(sp<Module> module);
 
     static void recognitionCallback(struct sound_trigger_recognition_event *event, void *cookie);
-    void sendRecognitionEvent(const sp<RecognitionEvent>& event);
-    void onRecognitionEvent(const sp<RecognitionEvent>& event);
+           sp<IMemory> prepareRecognitionEvent_l(struct sound_trigger_recognition_event *event);
+           void sendRecognitionEvent(struct sound_trigger_recognition_event *event, Module *module);
 
     static void soundModelCallback(struct sound_trigger_model_event *event, void *cookie);
+           sp<IMemory> prepareSoundModelEvent_l(struct sound_trigger_model_event *event);
+           void sendSoundModelEvent(struct sound_trigger_model_event *event, Module *module);
+
+           sp<IMemory> prepareServiceStateEvent_l(sound_trigger_service_state_t state);
+           void sendServiceStateEvent_l(sound_trigger_service_state_t state, Module *module);
+
+           void sendCallbackEvent_l(const sp<CallbackEvent>& event);
+           void onCallbackEvent(const sp<CallbackEvent>& event);
 
 private:
 
@@ -178,6 +197,8 @@
     volatile int32_t    mNextUniqueId;
     DefaultKeyedVector< sound_trigger_module_handle_t, sp<Module> >     mModules;
     sp<CallbackThread>  mCallbackThread;
+    sp<MemoryDealer>    mMemoryDealer;
+    bool                mCaptureState;
 };
 
 } // namespace android
diff --git a/soundtrigger/ISoundTriggerClient.cpp b/soundtrigger/ISoundTriggerClient.cpp
index 1d0c0ec..b0b4428 100644
--- a/soundtrigger/ISoundTriggerClient.cpp
+++ b/soundtrigger/ISoundTriggerClient.cpp
@@ -27,6 +27,8 @@
 
 enum {
     ON_RECOGNITION_EVENT = IBinder::FIRST_CALL_TRANSACTION,
+    ON_SOUNDMODEL_EVENT,
+    ON_SERVICE_STATE_CHANGE
 };
 
 class BpSoundTriggerClient: public BpInterface<ISoundTriggerClient>
@@ -47,6 +49,25 @@
                            data,
                            &reply);
     }
+
+    virtual void onSoundModelEvent(const sp<IMemory>& eventMemory)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISoundTriggerClient::getInterfaceDescriptor());
+        data.writeStrongBinder(eventMemory->asBinder());
+        remote()->transact(ON_SOUNDMODEL_EVENT,
+                           data,
+                           &reply);
+    }
+    virtual void onServiceStateChange(const sp<IMemory>& eventMemory)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISoundTriggerClient::getInterfaceDescriptor());
+        data.writeStrongBinder(eventMemory->asBinder());
+        remote()->transact(ON_SERVICE_STATE_CHANGE,
+                           data,
+                           &reply);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(SoundTriggerClient,
@@ -65,6 +86,20 @@
             onRecognitionEvent(eventMemory);
             return NO_ERROR;
         } break;
+        case ON_SOUNDMODEL_EVENT: {
+            CHECK_INTERFACE(ISoundTriggerClient, data, reply);
+            sp<IMemory> eventMemory = interface_cast<IMemory>(
+                data.readStrongBinder());
+            onSoundModelEvent(eventMemory);
+            return NO_ERROR;
+        } break;
+        case ON_SERVICE_STATE_CHANGE: {
+            CHECK_INTERFACE(ISoundTriggerClient, data, reply);
+            sp<IMemory> eventMemory = interface_cast<IMemory>(
+                data.readStrongBinder());
+            onServiceStateChange(eventMemory);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/soundtrigger/ISoundTriggerHwService.cpp b/soundtrigger/ISoundTriggerHwService.cpp
index c9a0c24..05728e9 100644
--- a/soundtrigger/ISoundTriggerHwService.cpp
+++ b/soundtrigger/ISoundTriggerHwService.cpp
@@ -37,6 +37,7 @@
 enum {
     LIST_MODULES = IBinder::FIRST_CALL_TRANSACTION,
     ATTACH,
+    SET_CAPTURE_STATE,
 };
 
 class BpSoundTriggerHwService: public BpInterface<ISoundTriggerHwService>
@@ -90,6 +91,18 @@
         return status;
     }
 
+    virtual status_t setCaptureState(bool active)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISoundTriggerHwService::getInterfaceDescriptor());
+        data.writeInt32(active);
+        status_t status = remote()->transact(SET_CAPTURE_STATE, data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+        }
+        return status;
+    }
+
 };
 
 IMPLEMENT_META_INTERFACE(SoundTriggerHwService, "android.hardware.ISoundTriggerHwService");
@@ -140,6 +153,13 @@
             }
             return NO_ERROR;
         } break;
+
+        case SET_CAPTURE_STATE: {
+            CHECK_INTERFACE(ISoundTriggerHwService, data, reply);
+            reply->writeInt32(setCaptureState((bool)data.readInt32()));
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp
index e43acd0..0015c30 100644
--- a/soundtrigger/SoundTrigger.cpp
+++ b/soundtrigger/SoundTrigger.cpp
@@ -113,6 +113,16 @@
 }
 
 
+status_t SoundTrigger::setCaptureState(bool active)
+{
+    ALOGV("setCaptureState(%d)", active);
+    const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService();
+    if (service == 0) {
+        return NO_INIT;
+    }
+    return service->setCaptureState(active);
+}
+
 // SoundTrigger
 SoundTrigger::SoundTrigger(sound_trigger_module_handle_t module,
                                  const sp<SoundTriggerCallback>& callback)
@@ -192,6 +202,31 @@
     }
 }
 
+void SoundTrigger::onSoundModelEvent(const sp<IMemory>& eventMemory)
+{
+    Mutex::Autolock _l(mLock);
+    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+        return;
+    }
+
+    if (mCallback != 0) {
+        mCallback->onSoundModelEvent(
+                (struct sound_trigger_model_event *)eventMemory->pointer());
+    }
+}
+
+void SoundTrigger::onServiceStateChange(const sp<IMemory>& eventMemory)
+{
+    Mutex::Autolock _l(mLock);
+    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+        return;
+    }
+
+    if (mCallback != 0) {
+        mCallback->onServiceStateChange(
+                *((sound_trigger_service_state_t *)eventMemory->pointer()));
+    }
+}
 
 //IBinder::DeathRecipient
 void SoundTrigger::binderDied(const wp<IBinder>& who __unused) {