Add sound trigger control by audio policy

Audio policy:
- Added active capture indication to sound trigger service:
recognition stops if concurrent capture is not supported.
- Added generation of reserved I/O handle and session ID for
utterance capture.

Sound trigger service
- Added sound model update callback handling.
- Added service state callback
- Simplified callback shared memory allocation.

Bug: 12378680.

Change-Id: Ib0292c2733e6df90fdae480633dd9953d0016ef1
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/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/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 440f5d0..f716358 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"
 
@@ -1119,6 +1120,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,
@@ -1149,6 +1161,7 @@
     inputDesc->mChannelMask = channelMask;
     inputDesc->mDevice = device;
     inputDesc->mSessions.add(session);
+    inputDesc->mIsSoundTrigger = isSoundTrigger;
 
     addInput(input, inputDesc);
     mpClientInterface->onAudioPortListUpdate();
@@ -1194,6 +1207,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.
@@ -1242,6 +1258,10 @@
         }
 
         resetInputDevice(input);
+
+        if (activeInputsCount() == 0) {
+            SoundTrigger::setCaptureState(false);
+        }
     }
     return NO_ERROR;
 }
@@ -2253,6 +2273,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)
 {
@@ -4013,7 +4058,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;
@@ -4198,6 +4244,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)
 {
@@ -4883,7 +4941,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..dd0f00f 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 {
@@ -477,15 +483,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 +578,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 +780,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) {