Merge "Use audio_patch_handle_t in startAudioSource() and stopAudioSource()"
diff --git a/Android.bp b/Android.bp
index edd3d04..53f8bec 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3,6 +3,7 @@
     from: "include/camera/ndk/",
     to: "camera",
     srcs: ["include/camera/ndk/**/*.h"],
+    license: "NOTICE",
 }
 
 ndk_headers {
@@ -10,6 +11,7 @@
     from: "include/ndk/",
     to: "media",
     srcs: ["include/ndk/**/*.h"],
+    license: "NOTICE",
 }
 
 subdirs = [
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index 755ec8e..8308095 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -44,4 +44,5 @@
      * @param lastFrameNumber Frame number of the last frame of the streaming request.
      */
     oneway void onRepeatingRequestError(in long lastFrameNumber);
+    oneway void onRequestQueueEmpty();
 }
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 7d78e2b..229b159 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -1347,6 +1347,12 @@
 }
 
 binder::Status
+CameraDevice::ServiceCallback::onRequestQueueEmpty() {
+    // onRequestQueueEmpty not yet implemented in NDK
+    return binder::Status::ok();
+}
+
+binder::Status
 CameraDevice::ServiceCallback::onRepeatingRequestError(int64_t lastFrameNumber) {
     binder::Status ret = binder::Status::ok();
 
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 051462b..eb8028b 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -74,6 +74,7 @@
         binder::Status onResultReceived(const CameraMetadata& metadata,
                               const CaptureResultExtras& resultExtras) override;
         binder::Status onPrepared(int streamId) override;
+        binder::Status onRequestQueueEmpty() override;
         binder::Status onRepeatingRequestError(int64_t lastFrameNumber) override;
       private:
         const wp<CameraDevice> mDevice;
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 828a758..b91e0f3 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -151,6 +151,7 @@
         SENT_RESULT,
         UNINITIALIZED,
         REPEATING_REQUEST_ERROR,
+        REQUEST_QUEUE_EMPTY,
     };
 
 protected:
@@ -225,6 +226,14 @@
         return binder::Status::ok();
     }
 
+    virtual binder::Status onRequestQueueEmpty() {
+        Mutex::Autolock l(mLock);
+        mLastStatus = REQUEST_QUEUE_EMPTY;
+        mStatusesHit.push_back(mLastStatus);
+        mStatusCondition.broadcast();
+        return binder::Status::ok();
+    }
+
     // Test helper functions:
 
     bool hadError() const {
diff --git a/drm/libmediadrm/Drm.cpp b/drm/libmediadrm/Drm.cpp
index 9ab08db..07e9414 100644
--- a/drm/libmediadrm/Drm.cpp
+++ b/drm/libmediadrm/Drm.cpp
@@ -334,6 +334,7 @@
         return -EINVAL;
     }
 
+    setListener(NULL);
     delete mPlugin;
     mPlugin = NULL;
 
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 311119b..b902cf5 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -163,7 +163,7 @@
     virtual status_t emptyGraphicBuffer(
             buffer_id buffer,
             const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
-            OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd) = 0;
+            OMX_TICKS timestamp, int fenceFd) = 0;
 
     virtual status_t getExtensionIndex(
             const char *parameter_name,
diff --git a/include/media/audiohal/DeviceHalInterface.h b/include/media/audiohal/DeviceHalInterface.h
index 2f7ed3a..caf01be 100644
--- a/include/media/audiohal/DeviceHalInterface.h
+++ b/include/media/audiohal/DeviceHalInterface.h
@@ -33,9 +33,6 @@
     // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
     virtual status_t getSupportedDevices(uint32_t *devices) = 0;
 
-    // Get the hardware module version.
-    virtual status_t getVersion(uint32_t *version) = 0;
-
     // Check to see if the audio hardware interface has been initialized.
     virtual status_t initCheck() = 0;
 
@@ -88,6 +85,9 @@
             audio_source_t source,
             sp<StreamInHalInterface> *inStream) = 0;
 
+    // Returns whether createAudioPatch and releaseAudioPatch operations are supported.
+    virtual status_t supportsAudioPatches(bool *supportsPatches) = 0;
+
     // Creates an audio patch between several source and sink ports.
     virtual status_t createAudioPatch(
             unsigned int num_sources,
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index 80f78b6..4b0f6a2 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -5,3 +5,4 @@
     group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
     ioprio rt 4
     writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    onrestart restart audio-hal-2-0
\ No newline at end of file
diff --git a/media/libaudiohal/DeviceHalLocal.cpp b/media/libaudiohal/DeviceHalLocal.cpp
index c5df8c8..78adfef 100644
--- a/media/libaudiohal/DeviceHalLocal.cpp
+++ b/media/libaudiohal/DeviceHalLocal.cpp
@@ -40,11 +40,6 @@
     return OK;
 }
 
-status_t DeviceHalLocal::getVersion(uint32_t *version) {
-    *version = mDev->common.version;
-    return OK;
-}
-
 status_t DeviceHalLocal::initCheck() {
     return mDev->init_check(mDev);
 }
@@ -139,17 +134,31 @@
     return openResult;
 }
 
+status_t DeviceHalLocal::supportsAudioPatches(bool *supportsPatches) {
+    *supportsPatches = version() >= AUDIO_DEVICE_API_VERSION_3_0;
+    return OK;
+}
+
 status_t DeviceHalLocal::createAudioPatch(
         unsigned int num_sources,
         const struct audio_port_config *sources,
         unsigned int num_sinks,
         const struct audio_port_config *sinks,
         audio_patch_handle_t *patch) {
-    return mDev->create_audio_patch(mDev, num_sources, sources, num_sinks, sinks, patch);
+    if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+        return mDev->create_audio_patch(
+                mDev, num_sources, sources, num_sinks, sinks, patch);
+    } else {
+        return INVALID_OPERATION;
+    }
 }
 
 status_t DeviceHalLocal::releaseAudioPatch(audio_patch_handle_t patch) {
-    return mDev->release_audio_patch(mDev, patch);
+    if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+        return mDev->release_audio_patch(mDev, patch);
+    } else {
+        return INVALID_OPERATION;
+    }
 }
 
 status_t DeviceHalLocal::getAudioPort(struct audio_port *port) {
@@ -157,7 +166,10 @@
 }
 
 status_t DeviceHalLocal::setAudioPortConfig(const struct audio_port_config *config) {
-    return mDev->set_audio_port_config(mDev, config);
+    if (version() >= AUDIO_DEVICE_API_VERSION_3_0)
+        return mDev->set_audio_port_config(mDev, config);
+    else
+        return INVALID_OPERATION;
 }
 
 status_t DeviceHalLocal::dump(int fd) {
diff --git a/media/libaudiohal/DeviceHalLocal.h b/media/libaudiohal/DeviceHalLocal.h
index eba360c..865f296 100644
--- a/media/libaudiohal/DeviceHalLocal.h
+++ b/media/libaudiohal/DeviceHalLocal.h
@@ -28,9 +28,6 @@
     // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
     virtual status_t getSupportedDevices(uint32_t *devices);
 
-    // Get the hardware module version.
-    virtual status_t getVersion(uint32_t *version);
-
     // Check to see if the audio hardware interface has been initialized.
     virtual status_t initCheck();
 
@@ -83,6 +80,9 @@
             audio_source_t source,
             sp<StreamInHalInterface> *inStream);
 
+    // Returns whether createAudioPatch and releaseAudioPatch operations are supported.
+    virtual status_t supportsAudioPatches(bool *supportsPatches);
+
     // Creates an audio patch between several source and sink ports.
     virtual status_t createAudioPatch(
             unsigned int num_sources,
@@ -115,6 +115,8 @@
 
     // The destructor automatically closes the device.
     virtual ~DeviceHalLocal();
+
+    uint32_t version() const { return mDev->common.version; }
 };
 
 } // namespace android
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 1901d8c..4bd1ab8 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -475,14 +475,13 @@
     virtual status_t emptyGraphicBuffer(
             buffer_id buffer,
             const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
-            OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd) {
+            OMX_TICKS timestamp, int fenceFd) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMXNode::getInterfaceDescriptor());
         data.writeInt32((int32_t)buffer);
         data.write(*graphicBuffer);
         data.writeInt32(flags);
         data.writeInt64(timestamp);
-        data.writeInt64(origTimestamp);
         data.writeInt32(fenceFd >= 0);
         if (fenceFd >= 0) {
             data.writeFileDescriptor(fenceFd, true /* takeOwnership */);
@@ -990,12 +989,10 @@
             data.read(*graphicBuffer);
             OMX_U32 flags = data.readInt32();
             OMX_TICKS timestamp = data.readInt64();
-            OMX_TICKS origTimestamp = data.readInt64();
             bool haveFence = data.readInt32();
             int fenceFd = haveFence ? ::dup(data.readFileDescriptor()) : -1;
             reply->writeInt32(emptyGraphicBuffer(
-                    buffer, graphicBuffer, flags,
-                    timestamp, origTimestamp, fenceFd));
+                    buffer, graphicBuffer, flags, timestamp, fenceFd));
 
             return NO_ERROR;
         }
diff --git a/media/libmedia/aidl/android/IGraphicBufferSource.aidl b/media/libmedia/aidl/android/IGraphicBufferSource.aidl
index e9bf739..a8dd309 100644
--- a/media/libmedia/aidl/android/IGraphicBufferSource.aidl
+++ b/media/libmedia/aidl/android/IGraphicBufferSource.aidl
@@ -27,7 +27,6 @@
     void configure(IOMXNode omxNode, int dataSpace);
     void setSuspend(boolean suspend);
     void setRepeatPreviousFrameDelayUs(long repeatAfterUs);
-    void setMaxTimestampGapUs(long maxGapUs);
     void setMaxFps(float maxFps);
     void setTimeLapseConfig(long timePerFrameUs, long timePerCaptureUs);
     void setStartTimeUs(long startTimeUs);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 822f154..c3274f0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -755,7 +755,7 @@
 
 status_t NuPlayer::Decoder::fetchInputData(sp<AMessage> &reply) {
     sp<ABuffer> accessUnit;
-    bool dropAccessUnit;
+    bool dropAccessUnit = true;
     do {
         status_t err = mSource->dequeueAccessUnit(mIsAudio, &accessUnit);
 
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index dbb5f0d..ed29859 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1723,8 +1723,12 @@
             mRepeatFrameDelayUs = -1ll;
         }
 
+        // only allow 32-bit value, since we pass it as U32 to OMX.
         if (!msg->findInt64("max-pts-gap-to-encoder", &mMaxPtsGapUs)) {
             mMaxPtsGapUs = -1ll;
+        } else if (mMaxPtsGapUs > INT32_MAX || mMaxPtsGapUs < 0) {
+            ALOGW("Unsupported value for max pts gap %lld", (long long) mMaxPtsGapUs);
+            mMaxPtsGapUs = -1ll;
         }
 
         if (!msg->findFloat("max-fps-to-encoder", &mMaxFps)) {
@@ -6569,9 +6573,14 @@
     }
 
     if (mCodec->mMaxPtsGapUs > 0ll) {
-        err = statusFromBinderStatus(
-                mCodec->mGraphicBufferSource->setMaxTimestampGapUs(
-                        mCodec->mMaxPtsGapUs));
+        OMX_PARAM_U32TYPE maxPtsGapParams;
+        InitOMXParams(&maxPtsGapParams);
+        maxPtsGapParams.nPortIndex = kPortIndexInput;
+        maxPtsGapParams.nU32 = (uint32_t) mCodec->mMaxPtsGapUs;
+
+        err = mCodec->mOMXNode->setParameter(
+                (OMX_INDEXTYPE)OMX_IndexParamMaxFrameDurationForBitrateControl,
+                &maxPtsGapParams, sizeof(maxPtsGapParams));
 
         if (err != OK) {
             ALOGE("[%s] Unable to configure max timestamp gap (err %d)",
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 436a960..5ab5f3e 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1097,14 +1097,16 @@
                             break;
                         }
 
-                        case STOPPING:
                         case RELEASING:
                         {
                             // Ignore the error, assuming we'll still get
-                            // the shutdown complete notification.
-
+                            // the shutdown complete notification. If we
+                            // don't, we'll timeout and force release.
                             sendErrorResponse = false;
-
+                        }
+                        // fall-thru
+                        case STOPPING:
+                        {
                             if (mFlags & kFlagSawMediaServerDie) {
                                 // MediaServer died, there definitely won't
                                 // be a shutdown complete notification after
@@ -1118,6 +1120,7 @@
                                     mComponentName.clear();
                                 }
                                 (new AMessage)->postReply(mReplyID);
+                                sendErrorResponse = false;
                             }
                             break;
                         }
@@ -1573,6 +1576,10 @@
 
                 case CodecBase::kWhatShutdownCompleted:
                 {
+                    if (mState == UNINITIALIZED) {
+                        // Ignore shutdown complete if we're already released.
+                        break;
+                    }
                     if (mState == STOPPING) {
                         setState(INITIALIZED);
                     } else {
@@ -1894,7 +1901,9 @@
                 }
             }
 
-            if (!((mFlags & kFlagIsComponentAllocated) && targetState == UNINITIALIZED) // See 1
+            bool isReleasingAllocatedComponent =
+                    (mFlags & kFlagIsComponentAllocated) && targetState == UNINITIALIZED;
+            if (!isReleasingAllocatedComponent // See 1
                     && mState != INITIALIZED
                     && mState != CONFIGURED && !isExecuting()) {
                 // 1) Permit release to shut down the component if allocated.
@@ -1918,6 +1927,14 @@
                 break;
             }
 
+            // If we're flushing, or we're stopping but received a release
+            // request, post the reply for the pending call first, and consider
+            // it done. The reply token will be replaced after this, and we'll
+            // no longer be able to reply.
+            if (mState == FLUSHING || mState == STOPPING) {
+                (new AMessage)->postReply(mReplyID);
+            }
+
             if (mFlags & kFlagSawMediaServerDie) {
                 // It's dead, Jim. Don't expect initiateShutdown to yield
                 // any useful results now...
@@ -1929,6 +1946,15 @@
                 break;
             }
 
+            // If we already have an error, component may not be able to
+            // complete the shutdown properly. If we're stopping, post the
+            // reply now with an error to unblock the client, client can
+            // release after the failure (instead of ANR).
+            if (msg->what() == kWhatStop && (mFlags & kFlagStickyError)) {
+                PostReplyWithError(replyID, getStickyError());
+                break;
+            }
+
             mReplyID = replyID;
             setState(msg->what() == kWhatStop ? STOPPING : RELEASING);
 
@@ -1940,6 +1966,7 @@
             if (mSoftRenderer != NULL && (mFlags & kFlagPushBlankBuffersOnShutdown)) {
                 pushBlankBuffersToNativeWindow(mSurface.get());
             }
+
             break;
         }
 
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index d911508..bda29fa 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -99,7 +99,7 @@
     status_t emptyGraphicBuffer(
             OMX::buffer_id buffer,
             const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
-            OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd);
+            OMX_TICKS timestamp, int fenceFd);
 
     status_t getExtensionIndex(
             const char *parameterName, OMX_INDEXTYPE *index);
@@ -162,9 +162,13 @@
     };
     SecureBufferType mSecureBufferType[2];
 
+    // Following are OMX parameters managed by us (instead of the component)
+    // OMX_IndexParamMaxFrameDurationForBitrateControl
     KeyedVector<int64_t, int64_t> mOriginalTimeUs;
-    bool mShouldRestorePts;
     bool mRestorePtsFailed;
+    int64_t mMaxTimestampGapUs;
+    int64_t mPrevOriginalTimeUs;
+    int64_t mPrevModifiedTimeUs;
 
     // For debug support
     char *mName;
@@ -250,6 +254,9 @@
 
     bool handleDataSpaceChanged(omx_message &msg);
 
+    status_t setMaxPtsGapUs(const void *params, size_t size);
+    int64_t getCodecTimestamp(OMX_TICKS timestamp);
+
     OMXNodeInstance(const OMXNodeInstance &);
     OMXNodeInstance &operator=(const OMXNodeInstance &);
 };
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index afb8173..4575d28 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -51,9 +51,7 @@
     mNumBufferAcquired(0),
     mEndOfStream(false),
     mEndOfStreamSent(false),
-    mMaxTimestampGapUs(-1ll),
     mPrevOriginalTimeUs(-1ll),
-    mPrevModifiedTimeUs(-1ll),
     mSkipFramesBeforeNs(-1ll),
     mRepeatAfterUs(-1ll),
     mRepeatLastFrameGeneration(0),
@@ -515,9 +513,7 @@
 }
 
 bool GraphicBufferSource::getTimestamp(
-        const BufferItem &item, int64_t *origTimeUs, int64_t *codecTimeUs) {
-    *origTimeUs = -1ll;
-
+        const BufferItem &item, int64_t *codecTimeUs) {
     int64_t timeUs = item.mTimestamp / 1000;
     timeUs += mInputBufferTimeOffsetUs;
 
@@ -558,29 +554,7 @@
             return false;
         }
 
-        if (mMaxTimestampGapUs > 0ll) {
-            //TODO: Fix the case when mMaxTimestampGapUs and mTimePerCaptureUs are both set.
-
-            /* Cap timestamp gap between adjacent frames to specified max
-             *
-             * In the scenario of cast mirroring, encoding could be suspended for
-             * prolonged periods. Limiting the pts gap to workaround the problem
-             * where encoder's rate control logic produces huge frames after a
-             * long period of suspension.
-             */
-            if (mPrevOriginalTimeUs >= 0ll) {
-                int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
-                timeUs = (timestampGapUs < mMaxTimestampGapUs ?
-                    timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
-            }
-            *origTimeUs = originalTimeUs;
-            ALOGV("IN  timestamp: %lld -> %lld",
-                static_cast<long long>(originalTimeUs),
-                static_cast<long long>(timeUs));
-        }
-
         mPrevOriginalTimeUs = originalTimeUs;
-        mPrevModifiedTimeUs = timeUs;
     }
 
     *codecTimeUs = timeUs;
@@ -590,8 +564,8 @@
 status_t GraphicBufferSource::submitBuffer_l(const BufferItem &item, int cbi) {
     ALOGV("submitBuffer_l: slot=%d, cbi=%d", item.mSlot, cbi);
 
-    int64_t origTimeUs, codecTimeUs;
-    if (!getTimestamp(item, &origTimeUs, &codecTimeUs)) {
+    int64_t codecTimeUs;
+    if (!getTimestamp(item, &codecTimeUs)) {
         return UNKNOWN_ERROR;
     }
 
@@ -605,8 +579,7 @@
     int fenceID = item.mFence->isValid() ? item.mFence->dup() : -1;
 
     status_t err = mOMXNode->emptyGraphicBuffer(
-            bufferID, buffer, OMX_BUFFERFLAG_ENDOFFRAME,
-            codecTimeUs, origTimeUs, fenceID);
+            bufferID, buffer, OMX_BUFFERFLAG_ENDOFFRAME, codecTimeUs, fenceID);
 
     if (err != OK) {
         ALOGW("WARNING: emptyGraphicBuffer failed: 0x%x", err);
@@ -641,7 +614,7 @@
     status_t err = mOMXNode->emptyGraphicBuffer(
             bufferID, NULL /* buffer */,
             OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS,
-            0 /* timestamp */, -1ll /* origTimestamp */, -1 /* fenceFd */);
+            0 /* timestamp */, -1 /* fenceFd */);
     if (err != OK) {
         ALOGW("emptyDirectBuffer EOS failed: 0x%x", err);
     } else {
@@ -855,9 +828,7 @@
         mSuspended = false;
         mEndOfStream = false;
         mEndOfStreamSent = false;
-        mMaxTimestampGapUs = -1ll;
         mPrevOriginalTimeUs = -1ll;
-        mPrevModifiedTimeUs = -1ll;
         mSkipFramesBeforeNs = -1ll;
         mRepeatAfterUs = -1ll;
         mRepeatLastFrameGeneration = 0;
@@ -928,20 +899,6 @@
     return Status::ok();
 }
 
-Status GraphicBufferSource::setMaxTimestampGapUs(int64_t maxGapUs) {
-    ALOGV("setMaxTimestampGapUs: maxGapUs=%lld", (long long)maxGapUs);
-
-    Mutex::Autolock autoLock(mMutex);
-
-    if (mExecuting || maxGapUs <= 0ll) {
-        return Status::fromServiceSpecificError(INVALID_OPERATION);
-    }
-
-    mMaxTimestampGapUs = maxGapUs;
-
-    return Status::ok();
-}
-
 Status GraphicBufferSource::setTimeOffsetUs(int64_t timeOffsetUs) {
     Mutex::Autolock autoLock(mMutex);
 
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 045a86a..80fe078 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -120,15 +120,6 @@
     // state and once this behaviour is specified it cannot be reset.
     Status setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) override;
 
-    // When set, the timestamp fed to the encoder will be modified such that
-    // the gap between two adjacent frames is capped at maxGapUs. Timestamp
-    // will be restored to the original when the encoded frame is returned to
-    // the client.
-    // This is to solve a problem in certain real-time streaming case, where
-    // encoder's rate control logic produces huge frames after a long period
-    // of suspension on input.
-    Status setMaxTimestampGapUs(int64_t maxGapUs) override;
-
     // Sets the input buffer timestamp offset.
     // When set, the sample's timestamp will be adjusted with the timeOffsetUs.
     Status setTimeOffsetUs(int64_t timeOffsetUs) override;
@@ -220,7 +211,7 @@
 
     void setLatestBuffer_l(const BufferItem &item);
     bool repeatLatestBuffer_l();
-    bool getTimestamp(const BufferItem &item, int64_t *timeUs, int64_t *codecTimeUs);
+    bool getTimestamp(const BufferItem &item, int64_t *codecTimeUs);
 
     // called when the data space of the input buffer changes
     void onDataSpaceChanged_l(android_dataspace dataSpace, android_pixel_format pixelFormat);
@@ -279,9 +270,7 @@
         kRepeatLastFrameCount = 10,
     };
 
-    int64_t mMaxTimestampGapUs;
     int64_t mPrevOriginalTimeUs;
-    int64_t mPrevModifiedTimeUs;
     int64_t mSkipFramesBeforeNs;
 
     sp<FrameDropper> mFrameDropper;
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 2a4bd15..41f3e4a 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -340,8 +340,10 @@
       mQueriedProhibitedExtensions(false),
       mQuirks(0),
       mBufferIDCount(0),
-      mShouldRestorePts(false),
-      mRestorePtsFailed(false)
+      mRestorePtsFailed(false),
+      mMaxTimestampGapUs(-1ll),
+      mPrevOriginalTimeUs(-1ll),
+      mPrevModifiedTimeUs(-1ll)
 {
     mName = ADebug::GetDebugName(name);
     DEBUG = ADebug::GetDebugLevelFromProperty(name, "debug.stagefright.omx-debug");
@@ -546,18 +548,17 @@
         "OMX.google.android.index.getAndroidNativeBufferUsage",
     };
 
-    if ((index > OMX_IndexComponentStartUnused && index <= OMX_IndexParamStandardComponentRole)
-            || (index > OMX_IndexPortStartUnused && index <= OMX_IndexParamCompBufferSupplier)
-            || (index > OMX_IndexAudioStartUnused && index <= OMX_IndexConfigAudioChannelVolume)
-            || (index > OMX_IndexVideoStartUnused && index <= OMX_IndexConfigVideoNalSize)
-            || (index > OMX_IndexCommonStartUnused
-                    && index <= OMX_IndexConfigCommonTransitionEffect)
+    if ((index > OMX_IndexComponentStartUnused && index < OMX_IndexComponentEndUnused)
+            || (index > OMX_IndexPortStartUnused && index < OMX_IndexPortEndUnused)
+            || (index > OMX_IndexAudioStartUnused && index < OMX_IndexAudioEndUnused)
+            || (index > OMX_IndexVideoStartUnused && index < OMX_IndexVideoEndUnused)
+            || (index > OMX_IndexCommonStartUnused && index < OMX_IndexCommonEndUnused)
             || (index > (OMX_INDEXTYPE)OMX_IndexExtAudioStartUnused
-                    && index <= (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported)
+                    && index < (OMX_INDEXTYPE)OMX_IndexExtAudioEndUnused)
             || (index > (OMX_INDEXTYPE)OMX_IndexExtVideoStartUnused
-                    && index <= (OMX_INDEXTYPE)OMX_IndexConfigAndroidVideoTemporalLayering)
+                    && index < (OMX_INDEXTYPE)OMX_IndexExtVideoEndUnused)
             || (index > (OMX_INDEXTYPE)OMX_IndexExtOtherStartUnused
-                    && index <= (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits)) {
+                    && index < (OMX_INDEXTYPE)OMX_IndexExtOtherEndUnused)) {
         return false;
     }
 
@@ -598,6 +599,10 @@
     OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
     CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
 
+    if (extIndex == OMX_IndexParamMaxFrameDurationForBitrateControl) {
+        return setMaxPtsGapUs(params, size);
+    }
+
     if (isProhibitedIndex_l(index)) {
         android_errorWriteLog(0x534e4554, "29422020");
         return BAD_INDEX;
@@ -1524,7 +1529,7 @@
 // like emptyBuffer, but the data is already in header->pBuffer
 status_t OMXNodeInstance::emptyGraphicBuffer(
         OMX::buffer_id buffer, const sp<GraphicBuffer> &graphicBuffer,
-        OMX_U32 flags, OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd) {
+        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
     Mutex::Autolock autoLock(mLock);
 
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
@@ -1541,13 +1546,7 @@
         return err;
     }
 
-    // If we're required to restore original timestamp, origTimestamp will
-    // be set to non-negative number for all frames. If it's not required
-    // client will set it to -1ll for all frames.
-    if (origTimestamp >= 0ll && !mRestorePtsFailed) {
-        mShouldRestorePts = true;
-        mOriginalTimeUs.add(timestamp, origTimestamp);
-    }
+    int64_t codecTimeUs = getCodecTimestamp(timestamp);
 
     header->nOffset = 0;
     if (graphicBuffer == NULL) {
@@ -1557,13 +1556,55 @@
     } else {
         header->nFilledLen = sizeof(VideoNativeMetadata);
     }
-    return emptyBuffer_l(header, flags, timestamp, (intptr_t)header->pBuffer, fenceFd);
+    return emptyBuffer_l(header, flags, codecTimeUs, (intptr_t)header->pBuffer, fenceFd);
+}
+
+status_t OMXNodeInstance::setMaxPtsGapUs(const void *params, size_t size) {
+    if (params == NULL || size != sizeof(OMX_PARAM_U32TYPE)) {
+        CLOG_ERROR(setMaxPtsGapUs, BAD_VALUE, "invalid params (%p,%zu)", params, size);
+        return BAD_VALUE;
+    }
+
+    mMaxTimestampGapUs = (int64_t)((OMX_PARAM_U32TYPE*)params)->nU32;
+
+    return OK;
+}
+
+int64_t OMXNodeInstance::getCodecTimestamp(OMX_TICKS timestamp) {
+    int64_t originalTimeUs = timestamp;
+
+    if (mMaxTimestampGapUs > 0ll) {
+        /* Cap timestamp gap between adjacent frames to specified max
+         *
+         * In the scenario of cast mirroring, encoding could be suspended for
+         * prolonged periods. Limiting the pts gap to workaround the problem
+         * where encoder's rate control logic produces huge frames after a
+         * long period of suspension.
+         */
+        if (mPrevOriginalTimeUs >= 0ll) {
+            int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
+            timestamp = (timestampGapUs < mMaxTimestampGapUs ?
+                timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
+        }
+        ALOGV("IN  timestamp: %lld -> %lld",
+            static_cast<long long>(originalTimeUs),
+            static_cast<long long>(timestamp));
+    }
+
+    mPrevOriginalTimeUs = originalTimeUs;
+    mPrevModifiedTimeUs = timestamp;
+
+    if (mMaxTimestampGapUs > 0ll && !mRestorePtsFailed) {
+        mOriginalTimeUs.add(timestamp, originalTimeUs);
+    }
+
+    return timestamp;
 }
 
 void OMXNodeInstance::codecBufferFilled(omx_message &msg) {
     Mutex::Autolock autoLock(mBufferIDLock);
 
-    if (!mShouldRestorePts || mRestorePtsFailed) {
+    if (mMaxTimestampGapUs <= 0ll || mRestorePtsFailed) {
         return;
     }
 
@@ -1583,12 +1624,6 @@
             ALOGW("giving up limiting timestamp gap (pts = %lld)", timestamp);
             mRestorePtsFailed = true;
         }
-        if (mOriginalTimeUs.size() > BufferQueue::NUM_BUFFER_SLOTS) {
-            // something terribly wrong must have happened, giving up...
-            ALOGE("mOriginalTimeUs has too many entries (%zu)",
-                    mOriginalTimeUs.size());
-            mRestorePtsFailed = true;
-        }
     }
 }
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 6c71f60..04fb8ba 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -67,8 +67,6 @@
 #include <mediautils/BatteryNotifier.h>
 #include <private/android_filesystem_config.h>
 
-#include <hardware/audio.h>  // for AUDIO_HARDWARE_MODULE_...
-
 // ----------------------------------------------------------------------------
 
 // Note: the following macro is used for extremely verbose logging message.  In
diff --git a/services/audioflinger/AudioHwDevice.cpp b/services/audioflinger/AudioHwDevice.cpp
index 28110a2..b109d06 100644
--- a/services/audioflinger/AudioHwDevice.cpp
+++ b/services/audioflinger/AudioHwDevice.cpp
@@ -93,10 +93,10 @@
     return status;
 }
 
-uint32_t AudioHwDevice::version() const
-{
-    uint32_t result;
-    return mHwDevice->getVersion(&result) == OK ? result : 0;
+bool AudioHwDevice::supportsAudioPatches() const {
+    bool result;
+    return mHwDevice->supportsAudioPatches(&result) == OK ? result : false;
 }
 
+
 }; // namespace android
diff --git a/services/audioflinger/AudioHwDevice.h b/services/audioflinger/AudioHwDevice.h
index ebb8911..eb826c6 100644
--- a/services/audioflinger/AudioHwDevice.h
+++ b/services/audioflinger/AudioHwDevice.h
@@ -58,7 +58,6 @@
     audio_module_handle_t handle() const { return mHandle; }
     const char *moduleName() const { return mModuleName; }
     sp<DeviceHalInterface> hwDevice() const { return mHwDevice; }
-    uint32_t version() const;
 
     /** This method creates and opens the audio hardware output stream.
      * The "address" parameter qualifies the "devices" audio device type if needed.
@@ -75,6 +74,8 @@
             struct audio_config *config,
             const char *address);
 
+    bool supportsAudioPatches() const;
+
 private:
     const audio_module_handle_t mHandle;
     const char * const          mModuleName;
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 93f634a..591a49e 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -27,8 +27,6 @@
 #include "ServiceUtilities.h"
 #include <media/AudioParameter.h>
 
-#include <hardware/audio.h>  // for AUDIO_DEVICE_API_VERSION_...
-
 // ----------------------------------------------------------------------------
 
 // Note: the following macro is used for extremely verbose logging message.  In
@@ -249,11 +247,11 @@
             // - special patch request with 2 sources (reuse one existing output mix) OR
             // - Device to device AND
             //    - source HW module != destination HW module OR
-            //    - audio HAL version < 3.0
+            //    - audio HAL does not support audio patches creation
             if ((patch->num_sources == 2) ||
                 ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
                  ((patch->sinks[0].ext.device.hw_module != srcModule) ||
-                  (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0)))) {
+                  !audioHwDevice->supportsAudioPatches()))) {
                 if (patch->num_sources == 2) {
                     if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
                             (patch->num_sinks != 0 && patch->sinks[0].ext.device.hw_module !=
@@ -341,17 +339,13 @@
                     }
                     status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
                 } else {
-                    if (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) {
-                        status = INVALID_OPERATION;
-                        goto exit;
-                    }
-
                     sp<DeviceHalInterface> hwDevice = audioHwDevice->hwDevice();
                     status = hwDevice->createAudioPatch(patch->num_sources,
                                                         patch->sources,
                                                         patch->num_sinks,
                                                         patch->sinks,
                                                         &halHandle);
+                    if (status == INVALID_OPERATION) goto exit;
                 }
             }
         } break;
@@ -620,10 +614,6 @@
                 status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
             } else {
                 AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
-                if (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) {
-                    status = INVALID_OPERATION;
-                    break;
-                }
                 sp<DeviceHalInterface> hwDevice = audioHwDevice->hwDevice();
                 status = hwDevice->releaseAudioPatch(removedPatch->mHalHandle);
             }
@@ -688,13 +678,7 @@
     }
 
     AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
-    if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
-        sp<DeviceHalInterface> hwDevice = audioHwDevice->hwDevice();
-        return hwDevice->setAudioPortConfig(config);
-    } else {
-        return INVALID_OPERATION;
-    }
-    return NO_ERROR;
+    return audioHwDevice->hwDevice()->setAudioPortConfig(config);
 }
 
 } // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index e661a3b..6b23e56 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -53,8 +53,6 @@
 
 #include <powermanager/PowerManager.h>
 
-#include <hardware/audio.h>  // for AUDIO_DEVICE_API_VERSION_...
-
 #include "AudioFlinger.h"
 #include "AudioMixer.h"
 #include "BufferProviders.h"
@@ -3492,7 +3490,7 @@
     mOutDevice = type;
     mPatch = *patch;
 
-    if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+    if (mOutput->audioHwDev->supportsAudioPatches()) {
         sp<DeviceHalInterface> hwDevice = mOutput->audioHwDev->hwDevice();
         status = hwDevice->createAudioPatch(patch->num_sources,
                                             patch->sources,
@@ -3542,7 +3540,7 @@
 
     mOutDevice = AUDIO_DEVICE_NONE;
 
-    if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+    if (mOutput->audioHwDev->supportsAudioPatches()) {
         sp<DeviceHalInterface> hwDevice = mOutput->audioHwDev->hwDevice();
         status = hwDevice->releaseAudioPatch(handle);
     } else {
@@ -7612,7 +7610,7 @@
         }
     }
 
-    if (mInput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+    if (mInput->audioHwDev->supportsAudioPatches()) {
         sp<DeviceHalInterface> hwDevice = mInput->audioHwDev->hwDevice();
         status = hwDevice->createAudioPatch(patch->num_sources,
                                             patch->sources,
@@ -7652,7 +7650,7 @@
 
     mInDevice = AUDIO_DEVICE_NONE;
 
-    if (mInput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+    if (mInput->audioHwDev->supportsAudioPatches()) {
         sp<DeviceHalInterface> hwDevice = mInput->audioHwDev->hwDevice();
         status = hwDevice->releaseAudioPatch(handle);
     } else {
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 99c0cd2..ded2285 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -118,7 +118,7 @@
                                         audio_format_t targetFormat);
 
     audio_module_handle_t getModuleHandle() const;
-    uint32_t getModuleVersion() const;
+    uint32_t getModuleVersionMajor() const;
     const char *getModuleName() const;
 
     bool useInputChannelMask() const
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index 3a31672..29b6b9c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -18,7 +18,6 @@
 
 #include "DeviceDescriptor.h"
 #include "AudioRoute.h"
-#include <hardware/audio.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 #include <utils/Errors.h>
@@ -40,7 +39,7 @@
 class HwModule : public RefBase
 {
 public:
-    explicit HwModule(const char *name, uint32_t halVersion = AUDIO_DEVICE_API_VERSION_MIN);
+    explicit HwModule(const char *name, uint32_t halVersionMajor = 0, uint32_t halVersionMinor = 0);
     ~HwModule();
 
     const char *getName() const { return mName.string(); }
@@ -55,8 +54,11 @@
 
     void setProfiles(const IOProfileCollection &profiles);
 
-    void setHalVersion(uint32_t halVersion) { mHalVersion = halVersion; }
-    uint32_t getHalVersion() const { return mHalVersion; }
+    void setHalVersion(uint32_t major, uint32_t minor) {
+        mHalVersion = (major << 8) | (minor & 0xff);
+    }
+    uint32_t getHalVersionMajor() const { return mHalVersion >> 8; }
+    uint32_t getHalVersionMinor() const { return mHalVersion & 0xff; }
 
     sp<DeviceDescriptor> getRouteSinkDevice(const sp<AudioRoute> &route) const;
     DeviceVector getRouteSourceDevices(const sp<AudioRoute> &route) const;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 31bf95c..aac23b4 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -50,12 +50,12 @@
     return mModule->mHandle;
 }
 
-uint32_t AudioPort::getModuleVersion() const
+uint32_t AudioPort::getModuleVersionMajor() const
 {
     if (mModule == 0) {
         return 0;
     }
-    return mModule->getHalVersion();
+    return mModule->getHalVersionMajor();
 }
 
 const char *AudioPort::getModuleName() const
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index 643ac1e..d751f07 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -357,9 +357,8 @@
         } else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) {
             uint32_t major, minor;
             sscanf((char *)node->value, "%u.%u", &major, &minor);
-            module->setHalVersion(HARDWARE_DEVICE_API_VERSION(major, minor));
-            ALOGV("loadGlobalConfig() mHalVersion = %04x major %u minor %u",
-                  module->getHalVersion(), major, minor);
+            module->setHalVersion(major, minor);
+            ALOGV("loadGlobalConfig() mHalVersion = major %u minor %u", major, minor);
         }
         node = node->next;
     }
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 356aef1..cc56fb8 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -25,11 +25,11 @@
 
 namespace android {
 
-HwModule::HwModule(const char *name, uint32_t halVersion)
+HwModule::HwModule(const char *name, uint32_t halVersionMajor, uint32_t halVersionMinor)
     : mName(String8(name)),
-      mHandle(AUDIO_MODULE_HANDLE_NONE),
-      mHalVersion(halVersion)
+      mHandle(AUDIO_MODULE_HANDLE_NONE)
 {
+    setHalVersion(halVersionMajor, halVersionMinor);
 }
 
 HwModule::~HwModule()
@@ -227,7 +227,7 @@
     result.append(buffer);
     snprintf(buffer, SIZE, "  - handle: %d\n", mHandle);
     result.append(buffer);
-    snprintf(buffer, SIZE, "  - version: %u.%u\n", mHalVersion >> 8, mHalVersion & 0xFF);
+    snprintf(buffer, SIZE, "  - version: %u.%u\n", getHalVersionMajor(), getHalVersionMinor());
     result.append(buffer);
     write(fd, result.string(), result.size());
     if (mOutputProfiles.size()) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 3e5bb7d..44f382b 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -418,19 +418,17 @@
         ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
         return BAD_VALUE;
     }
-    uint32_t version = AUDIO_DEVICE_API_VERSION_MIN;
+    uint32_t versionMajor = 0, versionMinor = 0;
     string versionLiteral = getXmlAttribute(root, Attributes::version);
     if (!versionLiteral.empty()) {
-        uint32_t major, minor;
-        sscanf(versionLiteral.c_str(), "%u.%u", &major, &minor);
-        version = HARDWARE_DEVICE_API_VERSION(major, minor);
-        ALOGV("%s: mHalVersion = %04x major %u minor %u",  __FUNCTION__,
-              version, major, minor);
+        sscanf(versionLiteral.c_str(), "%u.%u", &versionMajor, &versionMinor);
+        ALOGV("%s: mHalVersion = major %u minor %u",  __FUNCTION__,
+              versionMajor, versionMajor);
     }
 
     ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
 
-    module = new Element(name.c_str(), version);
+    module = new Element(name.c_str(), versionMajor, versionMinor);
 
     // Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
     MixPortTraits::Collection mixPorts;
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index d31429c..5f0557c 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -320,8 +320,7 @@
             if (((availableInputDevices.types() &
                     AUDIO_DEVICE_IN_TELEPHONY_RX & ~AUDIO_DEVICE_BIT_IN) == 0) ||
                     (((txDevice & availPrimaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
-                         (primaryOutput->getAudioPort()->getModuleVersion() <
-                             AUDIO_DEVICE_API_VERSION_3_0))) {
+                         (primaryOutput->getAudioPort()->getModuleVersionMajor() < 3))) {
                 availableOutputDevicesType = availPrimaryOutputDevices;
             }
         }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 2d5afad..2f01b02 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -37,6 +37,7 @@
 #include <media/AudioPolicyHelper.h>
 #include <soundtrigger/SoundTrigger.h>
 #include <system/audio.h>
+#include <audio_policy_conf.h>
 #include "AudioPolicyManager.h"
 #ifndef USE_XML_AUDIO_POLICY_CONF
 #include <ConfigParsingUtils.h>
@@ -2721,7 +2722,7 @@
                 // - source and sink devices are on differnt HW modules OR
                 // - audio HAL version is < 3.0
                 if (!srcDeviceDesc->hasSameHwModuleAs(sinkDeviceDesc) ||
-                        (srcDeviceDesc->mModule->getHalVersion() < AUDIO_DEVICE_API_VERSION_3_0)) {
+                        (srcDeviceDesc->mModule->getHalVersionMajor() < 3)) {
                     // support only one sink device for now to simplify output selection logic
                     if (patch->num_sinks > 1) {
                         return INVALID_OPERATION;
@@ -3083,7 +3084,7 @@
 
     if (srcDeviceDesc->getAudioPort()->mModule->getHandle() ==
             sinkDeviceDesc->getAudioPort()->mModule->getHandle() &&
-            srcDeviceDesc->getAudioPort()->mModule->getHalVersion() >= AUDIO_DEVICE_API_VERSION_3_0 &&
+            srcDeviceDesc->getAudioPort()->mModule->getHalVersionMajor() >= 3 &&
             srcDeviceDesc->getAudioPort()->mGains.size() > 0) {
         ALOGV("%s AUDIO_DEVICE_API_VERSION_3_0", __FUNCTION__);
         //   create patch between src device and output device
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index b4f8e21..5166eb5 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -1210,6 +1210,14 @@
     }
 }
 
+void CameraDeviceClient::notifyRequestQueueEmpty() {
+    // Thread safe. Don't bother locking.
+    sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
+    if (remoteCb != 0) {
+        remoteCb->onRequestQueueEmpty();
+    }
+}
+
 void CameraDeviceClient::detachDevice() {
     if (mDevice == 0) return;
 
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index de283ea..68e453c 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -164,6 +164,7 @@
                              const CaptureResultExtras& resultExtras);
     virtual void notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp);
     virtual void notifyPrepared(int streamId);
+    virtual void notifyRequestQueueEmpty();
     virtual void notifyRepeatingRequestError(long lastFrameNumber);
 
     /**
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index ccd1e4d..7e26153 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -307,6 +307,12 @@
 }
 
 template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::notifyRequestQueueEmpty() {
+
+    ALOGV("%s: Request queue now empty", __FUNCTION__);
+}
+
+template <typename TClientBase>
 void Camera2ClientBase<TClientBase>::notifyRepeatingRequestError(long lastFrameNumber) {
     (void)lastFrameNumber;
 
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index dbbf638..9fd0a78 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -73,6 +73,7 @@
     virtual void          notifyAutoWhitebalance(uint8_t newState,
                                                  int triggerId);
     virtual void          notifyPrepared(int streamId);
+    virtual void          notifyRequestQueueEmpty();
     virtual void          notifyRepeatingRequestError(long lastFrameNumber);
 
     int                   getCameraId() const;
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 984d84b..f30afe3 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -204,6 +204,7 @@
         virtual void notifyShutter(const CaptureResultExtras &resultExtras,
                 nsecs_t timestamp) = 0;
         virtual void notifyPrepared(int streamId) = 0;
+        virtual void notifyRequestQueueEmpty() = 0;
 
         // Required only for API1
         virtual void notifyAutoFocus(uint8_t newState, int triggerId) = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 73a4124..2f3251f 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -686,7 +686,8 @@
 }
 
 status_t Camera3Device::convertMetadataListToRequestListLocked(
-        const List<const CameraMetadata> &metadataList, RequestList *requestList) {
+        const List<const CameraMetadata> &metadataList, bool repeating,
+        RequestList *requestList) {
     if (requestList == NULL) {
         CLOGE("requestList cannot be NULL.");
         return BAD_VALUE;
@@ -701,6 +702,8 @@
             return BAD_VALUE;
         }
 
+        newRequest->mRepeating = repeating;
+
         // Setup burst Id and request Id
         newRequest->mResultExtras.burstId = burstId++;
         if (it->exists(ANDROID_REQUEST_ID)) {
@@ -757,7 +760,8 @@
 
     RequestList requestList;
 
-    res = convertMetadataListToRequestListLocked(requests, /*out*/&requestList);
+    res = convertMetadataListToRequestListLocked(requests, repeating,
+            /*out*/&requestList);
     if (res != OK) {
         // error logged by previous call
         return res;
@@ -3535,6 +3539,12 @@
                 mRequestQueue.begin();
         nextRequest = *firstRequest;
         mRequestQueue.erase(firstRequest);
+        if (mRequestQueue.empty() && !nextRequest->mRepeating) {
+            sp<NotificationListener> listener = mListener.promote();
+            if (listener != NULL) {
+                listener->notifyRequestQueueEmpty();
+            }
+        }
     }
 
     // In case we've been unpaused by setPaused clearing mDoPause, need to
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 33429a6..31901bc 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -297,6 +297,8 @@
         // requests will be submitted to HAL at a time. The batch size for
         // the following 7 requests will be ignored by the request thread.
         int                                 mBatchSize;
+        //  Whether this request is from a repeating or repeating burst.
+        bool                                mRepeating;
     };
     typedef List<sp<CaptureRequest> > RequestList;
 
@@ -304,6 +306,7 @@
 
     status_t convertMetadataListToRequestListLocked(
             const List<const CameraMetadata> &metadataList,
+            bool repeating,
             /*out*/
             RequestList *requestList);
 
diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk
index c55ac7f..f719dc9 100644
--- a/services/soundtrigger/Android.mk
+++ b/services/soundtrigger/Android.mk
@@ -16,7 +16,6 @@
 
 include $(CLEAR_VARS)
 
-
 ifeq ($(SOUND_TRIGGER_USE_STUB_MODULE), 1)
     LOCAL_CFLAGS += -DSOUND_TRIGGER_USE_STUB_MODULE
 endif
@@ -35,12 +34,32 @@
     libmedia \
     libserviceutility
 
+
+ifeq ($(ENABLE_TREBLE),true)
+# Treble configuration
+LOCAL_CFLAGS += -DENABLE_TREBLE
+LOCAL_SRC_FILES +=               \
+    SoundTriggerHalHidl.cpp
+
+LOCAL_SHARED_LIBRARIES += \
+		libhwbinder \
+		libhidl \
+		libbase \
+		android.hardware.soundtrigger@2.0 \
+		android.hardware.audio.common@2.0
+else
+# libhardware configuration
+LOCAL_SRC_FILES +=               \
+    SoundTriggerHalLegacy.cpp
+endif
+
+
 LOCAL_C_INCLUDES += \
     $(TOPDIR)frameworks/av/services/audioflinger
 
 LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
 
-LOCAL_CFLAGS := -Wall -Werror
+LOCAL_CFLAGS += -Wall -Werror
 
 LOCAL_MODULE:= libsoundtriggerservice
 
diff --git a/services/soundtrigger/SoundTriggerHalHidl.cpp b/services/soundtrigger/SoundTriggerHalHidl.cpp
new file mode 100644
index 0000000..e71d742
--- /dev/null
+++ b/services/soundtrigger/SoundTriggerHalHidl.cpp
@@ -0,0 +1,628 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SoundTriggerHalHidl"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include "SoundTriggerHalHidl.h"
+#include <hidl/IServiceManager.h>
+#include <hwbinder/IPCThreadState.h>
+#include <hwbinder/ProcessState.h>
+
+namespace android {
+
+using android::hardware::Return;
+using android::hardware::ProcessState;
+using android::hardware::audio::common::V2_0::AudioDevice;
+
+pthread_once_t SoundTriggerHalHidl::sOnceControl = PTHREAD_ONCE_INIT;
+
+void SoundTriggerHalHidl::sOnceInit()
+{
+    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->startThreadPool();
+}
+
+/* static */
+sp<SoundTriggerHalInterface> SoundTriggerHalInterface::connectModule(const char *moduleName)
+{
+    return new SoundTriggerHalHidl(moduleName);
+}
+
+int SoundTriggerHalHidl::getProperties(struct sound_trigger_properties *properties)
+{
+    sp<ISoundTriggerHw> soundtrigger = getService();
+    if (soundtrigger == 0) {
+        return -ENODEV;
+    }
+
+    ISoundTriggerHw::Properties halProperties;
+    Return<void> hidlReturn;
+    int32_t halReturn;
+    {
+        AutoMutex lock(mHalLock);
+        hidlReturn = soundtrigger->getProperties([&](int rc, auto res) {
+            halReturn = rc;
+            halProperties = res;
+            ALOGI("getProperties res implementor %s", res.implementor.c_str());
+        });
+    }
+
+    int ret = 0;
+    if (hidlReturn.getStatus().isOk()) {
+        convertPropertiesFromHal(properties, &halProperties);
+    } else {
+        ret = (int)hidlReturn.getStatus().transactionError();
+        if (ret == -EPIPE) {
+            clearService();
+        }
+    }
+
+    return ret;
+}
+
+int SoundTriggerHalHidl::loadSoundModel(struct sound_trigger_sound_model *sound_model,
+                        sound_model_callback_t callback,
+                        void *cookie,
+                        sound_model_handle_t *handle)
+{
+    if (handle == NULL) {
+        return -EINVAL;
+    }
+
+    sp<ISoundTriggerHw> soundtrigger = getService();
+    if (soundtrigger == 0) {
+        return -ENODEV;
+    }
+
+    uint32_t modelId;
+    {
+        AutoMutex lock(mLock);
+        do {
+            modelId = nextUniqueId();
+            ALOGI("loadSoundModel modelId %u", modelId);
+            sp<SoundModel> model = mSoundModels.valueFor(modelId);
+            ALOGI("loadSoundModel model %p", model.get());
+        } while (mSoundModels.valueFor(modelId) != 0 && modelId != 0);
+    }
+    LOG_ALWAYS_FATAL_IF(modelId == 0,
+                        "loadSoundModel(): wrap around in sound model IDs, num loaded models %zd",
+                        mSoundModels.size());
+
+    ISoundTriggerHw::SoundModel *halSoundModel =
+            convertSoundModelToHal(sound_model);
+    if (halSoundModel == NULL) {
+        return -EINVAL;
+    }
+
+    Return<void> hidlReturn;
+    int32_t halReturn;
+    SoundModelHandle halHandle;
+    {
+        AutoMutex lock(mHalLock);
+        if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+            hidlReturn = soundtrigger->loadPhraseSoundModel(
+                    *(const ISoundTriggerHw::PhraseSoundModel *)halSoundModel,
+                    this, modelId, [&](int32_t retval, auto res) {
+                halReturn = retval;
+                halHandle = res;
+            });
+
+        } else {
+            hidlReturn = soundtrigger->loadSoundModel(*halSoundModel,
+                    this, modelId, [&](int32_t retval, auto res) {
+                halReturn = retval;
+                halHandle = res;
+            });
+        }
+    }
+
+    delete halSoundModel;
+
+    int ret = 0;
+    if (hidlReturn.getStatus().isOk()) {
+        AutoMutex lock(mLock);
+        *handle = (sound_model_handle_t)modelId;
+        sp<SoundModel> model = new SoundModel(*handle, callback, cookie, halHandle);
+        mSoundModels.add(*handle, model);
+    } else {
+        ret = (int)hidlReturn.getStatus().transactionError();
+        ALOGE("loadSoundModel error %d", ret);
+        if (ret == -EPIPE) {
+            clearService();
+        }
+    }
+
+
+    return ret;
+}
+
+int SoundTriggerHalHidl::unloadSoundModel(sound_model_handle_t handle)
+{
+    sp<ISoundTriggerHw> soundtrigger = getService();
+    if (soundtrigger == 0) {
+        return -ENODEV;
+    }
+
+    sp<SoundModel> model = removeModel(handle);
+    if (model == 0) {
+        ALOGE("unloadSoundModel model not found for handle %u", handle);
+        return -EINVAL;
+    }
+
+    Return<int32_t> halReturn(0);
+    {
+        AutoMutex lock(mHalLock);
+        halReturn = soundtrigger->unloadSoundModel(model->mHalHandle);
+    }
+
+    int ret = (int)halReturn.getStatus().transactionError();
+    ALOGE_IF(ret != 0, "unloadSoundModel error %d", ret);
+    if (ret == -EPIPE) {
+        clearService();
+    }
+
+    return ret;
+}
+
+int SoundTriggerHalHidl::startRecognition(sound_model_handle_t handle,
+                         const struct sound_trigger_recognition_config *config,
+                         recognition_callback_t callback,
+                         void *cookie)
+{
+    sp<ISoundTriggerHw> soundtrigger = getService();
+    if (soundtrigger == 0) {
+        return -ENODEV;
+    }
+
+    sp<SoundModel> model = getModel(handle);
+    if (model == 0) {
+        ALOGE("startRecognition model not found for handle %u", handle);
+        return -EINVAL;
+    }
+
+    model->mRecognitionCallback = callback;
+    model->mRecognitionCookie = cookie;
+
+    ISoundTriggerHw::RecognitionConfig *halConfig =
+            convertRecognitionConfigToHal(config);
+
+    Return<int32_t> halReturn(0);
+    {
+        AutoMutex lock(mHalLock);
+        halReturn = soundtrigger->startRecognition(model->mHalHandle, *halConfig, this, handle);
+    }
+
+    delete halConfig;
+
+    int ret = (int)halReturn.getStatus().transactionError();
+    ALOGE_IF(ret != 0, "startRecognition error %d", ret);
+    if (ret == -EPIPE) {
+        clearService();
+    }
+    return ret;
+}
+
+int SoundTriggerHalHidl::stopRecognition(sound_model_handle_t handle)
+{
+    sp<ISoundTriggerHw> soundtrigger = getService();
+    if (soundtrigger == 0) {
+        return -ENODEV;
+    }
+
+    sp<SoundModel> model = getModel(handle);
+    if (model == 0) {
+        ALOGE("stopRecognition model not found for handle %u", handle);
+        return -EINVAL;
+    }
+
+    Return<int32_t> halReturn(0);
+    {
+        AutoMutex lock(mHalLock);
+        halReturn = soundtrigger->stopRecognition(model->mHalHandle);
+    }
+
+    int ret = (int)halReturn.getStatus().transactionError();
+    ALOGE_IF(ret != 0, "stopRecognition error %d", ret);
+    if (ret == -EPIPE) {
+        clearService();
+    }
+    return ret;
+}
+
+int SoundTriggerHalHidl::stopAllRecognitions()
+{
+    sp<ISoundTriggerHw> soundtrigger = getService();
+    if (soundtrigger == 0) {
+        return -ENODEV;
+    }
+
+    Return<int32_t> halReturn(0);
+    {
+        AutoMutex lock(mHalLock);
+        Return<int32_t> halReturn = soundtrigger->stopAllRecognitions();
+    }
+
+    int ret = (int)halReturn.getStatus().transactionError();
+    ALOGE_IF(ret != 0, "stopAllRecognitions error %d", ret);
+    if (ret == -EPIPE) {
+        clearService();
+    }
+    return ret;
+}
+
+SoundTriggerHalHidl::SoundTriggerHalHidl(const char *moduleName)
+    : mModuleName(moduleName), mNextUniqueId(1)
+{
+}
+
+void SoundTriggerHalHidl::onFirstRef()
+{
+    pthread_once(&sOnceControl, &sOnceInit);
+}
+
+SoundTriggerHalHidl::~SoundTriggerHalHidl()
+{
+}
+
+sp<ISoundTriggerHw> SoundTriggerHalHidl::getService()
+{
+    AutoMutex lock(mLock);
+    if (mISoundTrigger == 0) {
+        if (mModuleName == NULL) {
+            mModuleName = "primary";
+        }
+        std::string serviceName = "sound_trigger.";
+        serviceName.append(mModuleName);
+        mISoundTrigger = ISoundTriggerHw::getService(serviceName);
+    }
+    return mISoundTrigger;
+}
+
+void SoundTriggerHalHidl::clearService()
+{
+    AutoMutex lock(mLock);
+    mISoundTrigger = 0;
+}
+
+sp<SoundTriggerHalHidl::SoundModel> SoundTriggerHalHidl::getModel(sound_model_handle_t handle)
+{
+    AutoMutex lock(mLock);
+    return mSoundModels.valueFor(handle);
+}
+
+sp<SoundTriggerHalHidl::SoundModel> SoundTriggerHalHidl::removeModel(sound_model_handle_t handle)
+{
+    AutoMutex lock(mLock);
+    sp<SoundModel> model = mSoundModels.valueFor(handle);
+    mSoundModels.removeItem(handle);
+    return model;
+}
+
+uint32_t SoundTriggerHalHidl::nextUniqueId()
+{
+    return (uint32_t) atomic_fetch_add_explicit(&mNextUniqueId,
+                (uint_fast32_t) 1, memory_order_acq_rel);
+}
+
+void SoundTriggerHalHidl::convertUuidToHal(Uuid *halUuid,
+                                           const sound_trigger_uuid_t *uuid)
+{
+    halUuid->timeLow = uuid->timeLow;
+    halUuid->timeMid = uuid->timeMid;
+    halUuid->versionAndTimeHigh = uuid->timeHiAndVersion;
+    halUuid->variantAndClockSeqHigh = uuid->clockSeq;
+    memcpy(halUuid->node.data(), &uuid->node[0], sizeof(uuid->node));
+}
+
+void SoundTriggerHalHidl::convertUuidFromHal(sound_trigger_uuid_t *uuid,
+                                             const Uuid *halUuid)
+{
+    uuid->timeLow = halUuid->timeLow;
+    uuid->timeMid = halUuid->timeMid;
+    uuid->timeHiAndVersion = halUuid->versionAndTimeHigh;
+    uuid->clockSeq = halUuid->variantAndClockSeqHigh;
+    memcpy(&uuid->node[0], halUuid->node.data(), sizeof(uuid->node));
+}
+
+void SoundTriggerHalHidl::convertPropertiesFromHal(
+        struct sound_trigger_properties *properties,
+        const ISoundTriggerHw::Properties *halProperties)
+{
+    strlcpy(properties->implementor,
+            halProperties->implementor.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
+    strlcpy(properties->description,
+            halProperties->description.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
+    properties->version = halProperties->version;
+    convertUuidFromHal(&properties->uuid, &halProperties->uuid);
+    properties->max_sound_models = halProperties->maxSoundModels;
+    properties->max_key_phrases = halProperties->maxKeyPhrases;
+    properties->max_users = halProperties->maxUsers;
+    properties->recognition_modes = halProperties->recognitionModes;
+    properties->capture_transition = (bool)halProperties->captureTransition;
+    properties->max_buffer_ms = halProperties->maxBufferMs;
+    properties->concurrent_capture = (bool)halProperties->concurrentCapture;
+    properties->trigger_in_event = (bool)halProperties->triggerInEvent;
+    properties->power_consumption_mw = halProperties->powerConsumptionMw;
+}
+
+void SoundTriggerHalHidl::convertTriggerPhraseToHal(
+        ISoundTriggerHw::Phrase *halTriggerPhrase,
+        const struct sound_trigger_phrase *triggerPhrase)
+{
+    halTriggerPhrase->id = triggerPhrase->id;
+    halTriggerPhrase->recognitionModes = triggerPhrase->recognition_mode;
+    halTriggerPhrase->users.setToExternal((uint32_t *)&triggerPhrase->users[0], triggerPhrase->num_users);
+    halTriggerPhrase->locale = triggerPhrase->locale;
+    halTriggerPhrase->text = triggerPhrase->text;
+}
+
+ISoundTriggerHw::SoundModel *SoundTriggerHalHidl::convertSoundModelToHal(
+        const struct sound_trigger_sound_model *soundModel)
+{
+    ISoundTriggerHw::SoundModel *halModel = NULL;
+    if (soundModel->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+        ISoundTriggerHw::PhraseSoundModel *halKeyPhraseModel =
+                new ISoundTriggerHw::PhraseSoundModel();
+        struct sound_trigger_phrase_sound_model *keyPhraseModel =
+                (struct sound_trigger_phrase_sound_model *)soundModel;
+        ISoundTriggerHw::Phrase *halPhrases =
+                new ISoundTriggerHw::Phrase[keyPhraseModel->num_phrases];
+
+
+        for (unsigned int i = 0; i < keyPhraseModel->num_phrases; i++) {
+            convertTriggerPhraseToHal(&halPhrases[i],
+                                      &keyPhraseModel->phrases[i]);
+        }
+        halKeyPhraseModel->phrases.setToExternal(halPhrases, keyPhraseModel->num_phrases);
+        // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+        halKeyPhraseModel->phrases.resize(keyPhraseModel->num_phrases);
+
+        delete[] halPhrases;
+
+        halModel = (ISoundTriggerHw::SoundModel *)halKeyPhraseModel;
+    } else {
+        halModel = new ISoundTriggerHw::SoundModel();
+    }
+    halModel->type = (SoundModelType)soundModel->type;
+    convertUuidToHal(&halModel->uuid, &soundModel->uuid);
+    convertUuidToHal(&halModel->vendorUuid, &soundModel->vendor_uuid);
+    halModel->data.setToExternal((uint8_t *)soundModel + soundModel->data_offset, soundModel->data_size);
+    halModel->data.resize(soundModel->data_size);
+
+    return halModel;
+}
+
+void SoundTriggerHalHidl::convertPhraseRecognitionExtraToHal(
+        PhraseRecognitionExtra *halExtra,
+        const struct sound_trigger_phrase_recognition_extra *extra)
+{
+    halExtra->id = extra->id;
+    halExtra->recognitionModes = extra->recognition_modes;
+    halExtra->confidenceLevel = extra->confidence_level;
+    ConfidenceLevel *halLevels =
+            new ConfidenceLevel[extra->num_levels];
+    for (unsigned int i = 0; i < extra->num_levels; i++) {
+        halLevels[i].userId = extra->levels[i].user_id;
+        halLevels[i].levelPercent = extra->levels[i].level;
+    }
+    halExtra->levels.setToExternal(halLevels, extra->num_levels);
+    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+    halExtra->levels.resize(extra->num_levels);
+
+    delete[] halLevels;
+}
+
+
+ISoundTriggerHw::RecognitionConfig *SoundTriggerHalHidl::convertRecognitionConfigToHal(
+        const struct sound_trigger_recognition_config *config)
+{
+    ISoundTriggerHw::RecognitionConfig *halConfig =
+            new ISoundTriggerHw::RecognitionConfig();
+
+    halConfig->captureHandle = config->capture_handle;
+    halConfig->captureDevice = (AudioDevice)config->capture_device;
+    halConfig->captureRequested = (uint32_t)config->capture_requested;
+
+    PhraseRecognitionExtra *halExtras =
+            new PhraseRecognitionExtra[config->num_phrases];
+
+    for (unsigned int i = 0; i < config->num_phrases; i++) {
+        convertPhraseRecognitionExtraToHal(&halExtras[i],
+                                  &config->phrases[i]);
+    }
+    halConfig->phrases.setToExternal(halExtras, config->num_phrases);
+    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+    halConfig->phrases.resize(config->num_phrases);
+
+    delete[] halExtras;
+
+    halConfig->data.setToExternal((uint8_t *)config + config->data_offset, config->data_size);
+
+    return halConfig;
+}
+
+
+// ISoundTriggerHwCallback
+::android::hardware::Return<void> SoundTriggerHalHidl::recognitionCallback(
+        const ISoundTriggerHwCallback::RecognitionEvent& halEvent,
+        CallbackCookie cookie)
+{
+    sp<SoundModel> model;
+    {
+        AutoMutex lock(mLock);
+        model = mSoundModels.valueFor((SoundModelHandle)cookie);
+        if (model == 0) {
+            return Return<void>();
+        }
+    }
+    struct sound_trigger_recognition_event *event = convertRecognitionEventFromHal(&halEvent);
+    if (event == NULL) {
+        return Return<void>();
+    }
+    event->model = model->mHandle;
+    model->mRecognitionCallback(event, model->mRecognitionCookie);
+
+    free(event);
+
+    return Return<void>();
+}
+
+::android::hardware::Return<void> SoundTriggerHalHidl::phraseRecognitionCallback(
+        const ISoundTriggerHwCallback::PhraseRecognitionEvent& halEvent,
+        CallbackCookie cookie)
+{
+    sp<SoundModel> model;
+    {
+        AutoMutex lock(mLock);
+        model = mSoundModels.valueFor((SoundModelHandle)cookie);
+        if (model == 0) {
+            return Return<void>();
+        }
+    }
+
+    struct sound_trigger_recognition_event *event = convertRecognitionEventFromHal(
+                                   (const ISoundTriggerHwCallback::RecognitionEvent *)&halEvent);
+    if (event == NULL) {
+        return Return<void>();
+    }
+
+    event->model = model->mHandle;
+    model->mRecognitionCallback(event, model->mRecognitionCookie);
+
+    free(event);
+
+    return Return<void>();
+}
+
+::android::hardware::Return<void> SoundTriggerHalHidl::soundModelCallback(
+        const ISoundTriggerHwCallback::ModelEvent& halEvent,
+        CallbackCookie cookie)
+{
+    sp<SoundModel> model;
+    {
+        AutoMutex lock(mLock);
+        model = mSoundModels.valueFor((SoundModelHandle)cookie);
+        if (model == 0) {
+            return Return<void>();
+        }
+    }
+
+    struct sound_trigger_model_event *event = convertSoundModelEventFromHal(&halEvent);
+    if (event == NULL) {
+        return Return<void>();
+    }
+
+    event->model = model->mHandle;
+    model->mSoundModelCallback(event, model->mSoundModelCookie);
+
+    free(event);
+
+    return Return<void>();
+}
+
+
+struct sound_trigger_model_event *SoundTriggerHalHidl::convertSoundModelEventFromHal(
+                                              const ISoundTriggerHwCallback::ModelEvent *halEvent)
+{
+    struct sound_trigger_model_event *event = (struct sound_trigger_model_event *)malloc(
+            sizeof(struct sound_trigger_model_event) +
+            halEvent->data.size());
+    if (event == NULL) {
+        return NULL;
+    }
+
+    event->status = (int)halEvent->status;
+    // event->model to be set by caller
+    event->data_offset = sizeof(struct sound_trigger_model_event);
+    event->data_size = halEvent->data.size();
+    uint8_t *dst = (uint8_t *)event + event->data_offset;
+    uint8_t *src = (uint8_t *)&halEvent->data[0];
+    memcpy(dst, src, halEvent->data.size());
+
+    return event;
+}
+
+void SoundTriggerHalHidl::convertPhraseRecognitionExtraFromHal(
+        struct sound_trigger_phrase_recognition_extra *extra,
+        const PhraseRecognitionExtra *halExtra)
+{
+    extra->id = halExtra->id;
+    extra->recognition_modes = halExtra->recognitionModes;
+    extra->confidence_level = halExtra->confidenceLevel;
+
+    size_t i;
+    for (i = 0; i < halExtra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) {
+        extra->levels[i].user_id = halExtra->levels[i].userId;
+        extra->levels[i].level = halExtra->levels[i].levelPercent;
+    }
+    extra->num_levels = (unsigned int)i;
+}
+
+
+struct sound_trigger_recognition_event *SoundTriggerHalHidl::convertRecognitionEventFromHal(
+        const ISoundTriggerHwCallback::RecognitionEvent *halEvent)
+{
+    struct sound_trigger_recognition_event *event;
+
+    if (halEvent->type == SoundModelType::KEYPHRASE) {
+        struct sound_trigger_phrase_recognition_event *phraseEvent =
+                (struct sound_trigger_phrase_recognition_event *)malloc(
+                        sizeof(struct sound_trigger_phrase_recognition_event) +
+                        halEvent->data.size());
+        if (phraseEvent == NULL) {
+            return NULL;
+        }
+        const ISoundTriggerHwCallback::PhraseRecognitionEvent *halPhraseEvent =
+                (const ISoundTriggerHwCallback::PhraseRecognitionEvent *)halEvent;
+
+        for (unsigned int i = 0; i < halPhraseEvent->phraseExtras.size(); i++) {
+            convertPhraseRecognitionExtraFromHal(&phraseEvent->phrase_extras[i],
+                                                 &halPhraseEvent->phraseExtras[i]);
+        }
+        phraseEvent->num_phrases = halPhraseEvent->phraseExtras.size();
+        event = (struct sound_trigger_recognition_event *)phraseEvent;
+        event->data_offset = sizeof(sound_trigger_phrase_recognition_event);
+    } else {
+        event = (struct sound_trigger_recognition_event *)malloc(
+                sizeof(struct sound_trigger_recognition_event) + halEvent->data.size());
+        if (event == NULL) {
+            return NULL;
+        }
+        event->data_offset = sizeof(sound_trigger_recognition_event);
+    }
+    event->status = (int)halEvent->status;
+    event->type = (sound_trigger_sound_model_type_t)halEvent->type;
+    // event->model to be set by caller
+    event->capture_available = (bool)halEvent->captureAvailable;
+    event->capture_session = halEvent->captureSession;
+    event->capture_delay_ms = halEvent->captureDelayMs;
+    event->capture_preamble_ms = halEvent->capturePreambleMs;
+    event->trigger_in_data = (bool)halEvent->triggerInData;
+    event->audio_config.sample_rate = halEvent->audioConfig.sampleRateHz;
+    event->audio_config.channel_mask = (audio_channel_mask_t)halEvent->audioConfig.channelMask;
+    event->audio_config.format = (audio_format_t)halEvent->audioConfig.format;
+
+    event->data_size = halEvent->data.size();
+    uint8_t *dst = (uint8_t *)event + event->data_offset;
+    uint8_t *src = (uint8_t *)&halEvent->data[0];
+    memcpy(dst, src, halEvent->data.size());
+
+    return event;
+}
+
+} // namespace android
diff --git a/services/soundtrigger/SoundTriggerHalHidl.h b/services/soundtrigger/SoundTriggerHalHidl.h
new file mode 100644
index 0000000..60404dc
--- /dev/null
+++ b/services/soundtrigger/SoundTriggerHalHidl.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_HAL_HIDL_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_HAL_HIDL_H
+
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+#include "SoundTriggerHalInterface.h"
+#include <android/hardware/soundtrigger/2.0/types.h>
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
+#include <android/hardware/soundtrigger/2.0/BnSoundTriggerHwCallback.h>
+
+namespace android {
+
+using android::hardware::audio::common::V2_0::Uuid;
+using android::hardware::soundtrigger::V2_0::ConfidenceLevel;
+using android::hardware::soundtrigger::V2_0::PhraseRecognitionExtra;
+using android::hardware::soundtrigger::V2_0::SoundModelType;
+using android::hardware::soundtrigger::V2_0::SoundModelHandle;
+using android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
+using android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
+
+class SoundTriggerHalHidl : public SoundTriggerHalInterface,
+                            public virtual ISoundTriggerHwCallback
+
+{
+public:
+        virtual int getProperties(struct sound_trigger_properties *properties);
+
+        /*
+         * Load a sound model. Once loaded, recognition of this model can be started and stopped.
+         * Only one active recognition per model at a time. The SoundTrigger service will handle
+         * concurrent recognition requests by different users/applications on the same model.
+         * The implementation returns a unique handle used by other functions (unload_sound_model(),
+         * start_recognition(), etc...
+         */
+        virtual int loadSoundModel(struct sound_trigger_sound_model *sound_model,
+                                sound_model_callback_t callback,
+                                void *cookie,
+                                sound_model_handle_t *handle);
+
+        /*
+         * Unload a sound model. A sound model can be unloaded to make room for a new one to overcome
+         * implementation limitations.
+         */
+        virtual int unloadSoundModel(sound_model_handle_t handle);
+
+        /* Start recognition on a given model. Only one recognition active at a time per model.
+         * Once recognition succeeds of fails, the callback is called.
+         * TODO: group recognition configuration parameters into one struct and add key phrase options.
+         */
+        virtual int startRecognition(sound_model_handle_t handle,
+                                 const struct sound_trigger_recognition_config *config,
+                                 recognition_callback_t callback,
+                                 void *cookie);
+
+        /* Stop recognition on a given model.
+         * The implementation does not have to call the callback when stopped via this method.
+         */
+        virtual int stopRecognition(sound_model_handle_t handle);
+
+        /* Stop recognition on all models.
+         * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_1 or above.
+         * If no implementation is provided, stop_recognition will be called for each running model.
+         */
+        virtual int stopAllRecognitions();
+
+        // RefBase
+        virtual     void        onFirstRef();
+
+        // ISoundTriggerHwCallback
+        virtual ::android::hardware::Return<void> recognitionCallback(
+                const ISoundTriggerHwCallback::RecognitionEvent& event, CallbackCookie cookie);
+        virtual ::android::hardware::Return<void> phraseRecognitionCallback(
+                const ISoundTriggerHwCallback::PhraseRecognitionEvent& event, int32_t cookie);
+        virtual ::android::hardware::Return<void> soundModelCallback(
+                const ISoundTriggerHwCallback::ModelEvent& event, CallbackCookie cookie);
+private:
+        class SoundModel : public RefBase {
+        public:
+            SoundModel(sound_model_handle_t handle, sound_model_callback_t callback,
+                       void *cookie, android::hardware::soundtrigger::V2_0::SoundModelHandle halHandle)
+                 : mHandle(handle), mHalHandle(halHandle),
+                   mSoundModelCallback(callback), mSoundModelCookie(cookie),
+                   mRecognitionCallback(NULL), mRecognitionCookie(NULL) {}
+            ~SoundModel() {}
+
+            sound_model_handle_t   mHandle;
+            android::hardware::soundtrigger::V2_0::SoundModelHandle mHalHandle;
+            sound_model_callback_t mSoundModelCallback;
+            void *                 mSoundModelCookie;
+            recognition_callback_t mRecognitionCallback;
+            void *                 mRecognitionCookie;
+        };
+
+        friend class SoundTriggerHalInterface;
+
+        explicit SoundTriggerHalHidl(const char *moduleName = NULL);
+        virtual  ~SoundTriggerHalHidl();
+
+        void convertUuidToHal(Uuid *halUuid,
+                              const sound_trigger_uuid_t *uuid);
+        void convertUuidFromHal(sound_trigger_uuid_t *uuid,
+                                const Uuid *halUuid);
+
+        void convertPropertiesFromHal(
+                struct sound_trigger_properties *properties,
+                const ISoundTriggerHw::Properties *halProperties);
+
+        void convertTriggerPhraseToHal(
+                ISoundTriggerHw::Phrase *halTriggerPhrase,
+                const struct sound_trigger_phrase *triggerPhrase);
+        ISoundTriggerHw::SoundModel *convertSoundModelToHal(
+                const struct sound_trigger_sound_model *soundModel);
+
+        void convertPhraseRecognitionExtraToHal(
+                PhraseRecognitionExtra *halExtra,
+                const struct sound_trigger_phrase_recognition_extra *extra);
+        ISoundTriggerHw::RecognitionConfig *convertRecognitionConfigToHal(
+                const struct sound_trigger_recognition_config *config);
+
+        struct sound_trigger_model_event *convertSoundModelEventFromHal(
+                                              const ISoundTriggerHwCallback::ModelEvent *halEvent);
+        void convertPhraseRecognitionExtraFromHal(
+                struct sound_trigger_phrase_recognition_extra *extra,
+                const PhraseRecognitionExtra *halExtra);
+        struct sound_trigger_recognition_event *convertRecognitionEventFromHal(
+                const ISoundTriggerHwCallback::RecognitionEvent *halEvent);
+
+        uint32_t nextUniqueId();
+        sp<ISoundTriggerHw> getService();
+        void clearService();
+        sp<SoundModel> getModel(sound_model_handle_t handle);
+        sp<SoundModel> removeModel(sound_model_handle_t handle);
+
+        static pthread_once_t sOnceControl;
+        static void sOnceInit();
+
+        Mutex mLock;
+        Mutex mHalLock;
+        const char *mModuleName;
+        volatile atomic_uint_fast32_t  mNextUniqueId;
+        // Effect chains without a valid thread
+        DefaultKeyedVector< sound_model_handle_t , sp<SoundModel> > mSoundModels;
+        sp<::android::hardware::soundtrigger::V2_0::ISoundTriggerHw> mISoundTrigger;
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_SOUNDTRIGGER_HAL_HIDL_H
diff --git a/services/soundtrigger/SoundTriggerHalInterface.h b/services/soundtrigger/SoundTriggerHalInterface.h
new file mode 100644
index 0000000..c083195
--- /dev/null
+++ b/services/soundtrigger/SoundTriggerHalInterface.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_HAL_INTERFACE_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_HAL_INTERFACE_H
+
+#include <utils/RefBase.h>
+#include <system/sound_trigger.h>
+#include <hardware/sound_trigger.h>
+
+namespace android {
+
+class SoundTriggerHalInterface : public virtual RefBase
+{
+public:
+        /* get a sound trigger HAL instance */
+        static sp<SoundTriggerHalInterface> connectModule(const char *moduleName);
+
+        virtual     ~SoundTriggerHalInterface() {}
+
+        virtual int getProperties(struct sound_trigger_properties *properties) = 0;
+
+        /*
+         * Load a sound model. Once loaded, recognition of this model can be started and stopped.
+         * Only one active recognition per model at a time. The SoundTrigger service will handle
+         * concurrent recognition requests by different users/applications on the same model.
+         * The implementation returns a unique handle used by other functions (unload_sound_model(),
+         * start_recognition(), etc...
+         */
+        virtual int loadSoundModel(struct sound_trigger_sound_model *sound_model,
+                                sound_model_callback_t callback,
+                                void *cookie,
+                                sound_model_handle_t *handle) = 0;
+
+        /*
+         * Unload a sound model. A sound model can be unloaded to make room for a new one to overcome
+         * implementation limitations.
+         */
+        virtual int unloadSoundModel(sound_model_handle_t handle) = 0;
+
+        /* Start recognition on a given model. Only one recognition active at a time per model.
+         * Once recognition succeeds of fails, the callback is called.
+         * TODO: group recognition configuration parameters into one struct and add key phrase options.
+         */
+        virtual int startRecognition(sound_model_handle_t handle,
+                                 const struct sound_trigger_recognition_config *config,
+                                 recognition_callback_t callback,
+                                 void *cookie) = 0;
+
+        /* Stop recognition on a given model.
+         * The implementation does not have to call the callback when stopped via this method.
+         */
+        virtual int stopRecognition(sound_model_handle_t handle) = 0;
+
+        /* Stop recognition on all models.
+         * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_1 or above.
+         * If no implementation is provided, stop_recognition will be called for each running model.
+         */
+        virtual int stopAllRecognitions() = 0;
+
+protected:
+        SoundTriggerHalInterface() {}
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_SOUNDTRIGGER_HAL_INTERFACE_H
diff --git a/services/soundtrigger/SoundTriggerHalLegacy.cpp b/services/soundtrigger/SoundTriggerHalLegacy.cpp
new file mode 100644
index 0000000..2b78818
--- /dev/null
+++ b/services/soundtrigger/SoundTriggerHalLegacy.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/Log.h>
+#include "SoundTriggerHalLegacy.h"
+
+namespace android {
+
+/* static */
+sp<SoundTriggerHalInterface> SoundTriggerHalInterface::connectModule(const char *moduleName)
+{
+    return new SoundTriggerHalLegacy(moduleName);
+}
+
+SoundTriggerHalLegacy::SoundTriggerHalLegacy(const char *moduleName)
+    : mModuleName(moduleName), mHwDevice(NULL)
+{
+}
+
+void SoundTriggerHalLegacy::onFirstRef()
+{
+    const hw_module_t *mod;
+    int rc;
+
+    if (mModuleName == NULL) {
+        mModuleName = "primary";
+    }
+
+    rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod);
+    if (rc != 0) {
+        ALOGE("couldn't load sound trigger module %s.%s (%s)",
+              SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
+        return;
+    }
+    rc = sound_trigger_hw_device_open(mod, &mHwDevice);
+    if (rc != 0) {
+        ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
+              SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
+        mHwDevice = NULL;
+        return;
+    }
+    if (mHwDevice->common.version < SOUND_TRIGGER_DEVICE_API_VERSION_1_0 ||
+            mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
+        ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version);
+        return;
+    }
+}
+
+SoundTriggerHalLegacy::~SoundTriggerHalLegacy()
+{
+    if (mHwDevice != NULL) {
+        sound_trigger_hw_device_close(mHwDevice);
+    }
+}
+
+int SoundTriggerHalLegacy::getProperties(struct sound_trigger_properties *properties)
+{
+    if (mHwDevice == NULL) {
+        return -ENODEV;
+    }
+    return mHwDevice->get_properties(mHwDevice, properties);
+}
+
+int SoundTriggerHalLegacy::loadSoundModel(struct sound_trigger_sound_model *sound_model,
+                        sound_model_callback_t callback,
+                        void *cookie,
+                        sound_model_handle_t *handle)
+{
+    if (mHwDevice == NULL) {
+        return -ENODEV;
+    }
+    return mHwDevice->load_sound_model(mHwDevice, sound_model, callback, cookie, handle);
+}
+
+int SoundTriggerHalLegacy::unloadSoundModel(sound_model_handle_t handle)
+{
+    if (mHwDevice == NULL) {
+        return -ENODEV;
+    }
+    return mHwDevice->unload_sound_model(mHwDevice, handle);
+}
+
+int SoundTriggerHalLegacy::startRecognition(sound_model_handle_t handle,
+                         const struct sound_trigger_recognition_config *config,
+                         recognition_callback_t callback,
+                         void *cookie)
+{
+    if (mHwDevice == NULL) {
+        return -ENODEV;
+    }
+    return mHwDevice->start_recognition(mHwDevice, handle, config, callback, cookie);
+}
+
+int SoundTriggerHalLegacy::stopRecognition(sound_model_handle_t handle)
+{
+    if (mHwDevice == NULL) {
+        return -ENODEV;
+    }
+    return mHwDevice->stop_recognition(mHwDevice, handle);
+}
+
+int SoundTriggerHalLegacy::stopAllRecognitions()
+{
+    if (mHwDevice == NULL) {
+        return -ENODEV;
+    }
+    if (mHwDevice->common.version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_1 &&
+     mHwDevice->stop_all_recognitions) {
+        return mHwDevice->stop_all_recognitions(mHwDevice);
+    }
+    return -ENOSYS;
+}
+
+} // namespace android
diff --git a/services/soundtrigger/SoundTriggerHalLegacy.h b/services/soundtrigger/SoundTriggerHalLegacy.h
new file mode 100644
index 0000000..52488de
--- /dev/null
+++ b/services/soundtrigger/SoundTriggerHalLegacy.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_HAL_LEGACY_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_HAL_LEGACY_H
+
+#include "SoundTriggerHalInterface.h"
+
+namespace android {
+
+class SoundTriggerHalLegacy : public SoundTriggerHalInterface
+
+{
+public:
+        virtual             ~SoundTriggerHalLegacy();
+
+        virtual int getProperties(struct sound_trigger_properties *properties);
+
+        /*
+         * Load a sound model. Once loaded, recognition of this model can be started and stopped.
+         * Only one active recognition per model at a time. The SoundTrigger service will handle
+         * concurrent recognition requests by different users/applications on the same model.
+         * The implementation returns a unique handle used by other functions (unload_sound_model(),
+         * start_recognition(), etc...
+         */
+        virtual int loadSoundModel(struct sound_trigger_sound_model *sound_model,
+                                sound_model_callback_t callback,
+                                void *cookie,
+                                sound_model_handle_t *handle);
+
+        /*
+         * Unload a sound model. A sound model can be unloaded to make room for a new one to overcome
+         * implementation limitations.
+         */
+        virtual int unloadSoundModel(sound_model_handle_t handle);
+
+        /* Start recognition on a given model. Only one recognition active at a time per model.
+         * Once recognition succeeds of fails, the callback is called.
+         * TODO: group recognition configuration parameters into one struct and add key phrase options.
+         */
+        virtual int startRecognition(sound_model_handle_t handle,
+                                 const struct sound_trigger_recognition_config *config,
+                                 recognition_callback_t callback,
+                                 void *cookie);
+
+        /* Stop recognition on a given model.
+         * The implementation does not have to call the callback when stopped via this method.
+         */
+        virtual int stopRecognition(sound_model_handle_t handle);
+
+        /* Stop recognition on all models.
+         * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_1 or above.
+         * If no implementation is provided, stop_recognition will be called for each running model.
+         */
+        int stopAllRecognitions();
+
+        // RefBase
+        virtual     void        onFirstRef();
+
+private:
+
+        friend class SoundTriggerHalInterface;
+
+        explicit SoundTriggerHalLegacy(const char *moduleName = NULL);
+
+        const char *mModuleName;
+        struct sound_trigger_hw_device*        mHwDevice;
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_SOUNDTRIGGER_HAL_LEGACY_H
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 6a52b9c..3ba7f62 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -32,17 +32,16 @@
 #include <binder/IServiceManager.h>
 #include <binder/MemoryBase.h>
 #include <binder/MemoryHeapBase.h>
-#include <hardware/sound_trigger.h>
+#include <system/sound_trigger.h>
 #include <ServiceUtilities.h>
 #include "SoundTriggerHwService.h"
 
-namespace android {
-
 #ifdef SOUND_TRIGGER_USE_STUB_MODULE
 #define HW_MODULE_PREFIX "stub"
 #else
 #define HW_MODULE_PREFIX "primary"
 #endif
+namespace android {
 
 SoundTriggerHwService::SoundTriggerHwService()
     : BnSoundTriggerHwService(),
@@ -54,30 +53,17 @@
 
 void SoundTriggerHwService::onFirstRef()
 {
-    const hw_module_t *mod;
     int rc;
-    sound_trigger_hw_device *dev;
 
-    rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, &mod);
-    if (rc != 0) {
-        ALOGE("couldn't load sound trigger module %s.%s (%s)",
-              SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, strerror(-rc));
-        return;
-    }
-    rc = sound_trigger_hw_device_open(mod, &dev);
-    if (rc != 0) {
-        ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
-              SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, strerror(-rc));
-        return;
-    }
-    if (dev->common.version < SOUND_TRIGGER_DEVICE_API_VERSION_1_0 ||
-        dev->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
-        ALOGE("wrong sound trigger hw device version %04x", dev->common.version);
-        return;
-    }
+    sp<SoundTriggerHalInterface> halInterface =
+            SoundTriggerHalInterface::connectModule(HW_MODULE_PREFIX);
 
+    if (halInterface == 0) {
+        ALOGW("could not connect to HAL");
+        return;
+    }
     sound_trigger_module_descriptor descriptor;
-    rc = dev->get_properties(dev, &descriptor.properties);
+    rc = halInterface->getProperties(&descriptor.properties);
     if (rc != 0) {
         ALOGE("could not read implementation properties");
         return;
@@ -88,7 +74,7 @@
                                                  descriptor.handle);
 
     sp<ISoundTriggerClient> client;
-    sp<Module> module = new Module(this, dev, descriptor, client);
+    sp<Module> module = new Module(this, halInterface, descriptor, client);
     mModules.add(descriptor.handle, module);
     mCallbackThread = new CallbackThread(this);
 }
@@ -98,9 +84,6 @@
     if (mCallbackThread != 0) {
         mCallbackThread->exit();
     }
-    for (size_t i = 0; i < mModules.size(); i++) {
-        sound_trigger_hw_device_close(mModules.valueAt(i)->hwDevice());
-    }
 }
 
 status_t SoundTriggerHwService::listModules(struct sound_trigger_module_descriptor *modules,
@@ -489,10 +472,10 @@
 #define LOG_TAG "SoundTriggerHwService::Module"
 
 SoundTriggerHwService::Module::Module(const sp<SoundTriggerHwService>& service,
-                                      sound_trigger_hw_device* hwDevice,
+                                      const sp<SoundTriggerHalInterface>& halInterface,
                                       sound_trigger_module_descriptor descriptor,
                                       const sp<ISoundTriggerClient>& client)
- : mService(service), mHwDevice(hwDevice), mDescriptor(descriptor),
+ : mService(service), mHalInterface(halInterface), mDescriptor(descriptor),
    mClient(client), mServiceState(SOUND_TRIGGER_STATE_NO_INIT)
 {
 }
@@ -510,10 +493,12 @@
         for (size_t i = 0; i < mModels.size(); i++) {
             sp<Model> model = mModels.valueAt(i);
             ALOGV("detach() unloading model %d", model->mHandle);
-            if (model->mState == Model::STATE_ACTIVE) {
-                mHwDevice->stop_recognition(mHwDevice, model->mHandle);
+            if (mHalInterface != 0) {
+                if (model->mState == Model::STATE_ACTIVE) {
+                    mHalInterface->stopRecognition(model->mHandle);
+                }
+                mHalInterface->unloadSoundModel(model->mHandle);
             }
-            mHwDevice->unload_sound_model(mHwDevice, model->mHandle);
         }
         mModels.clear();
     }
@@ -531,10 +516,12 @@
                                 sound_model_handle_t *handle)
 {
     ALOGV("loadSoundModel() handle");
+    if (mHalInterface == 0) {
+        return NO_INIT;
+    }
     if (!captureHotwordAllowed()) {
         return PERMISSION_DENIED;
     }
-
     if (modelMemory == 0 || modelMemory->pointer() == NULL) {
         ALOGE("loadSoundModel() modelMemory is 0 or has NULL pointer()");
         return BAD_VALUE;
@@ -566,7 +553,7 @@
         return INVALID_OPERATION;
     }
 
-    status_t status = mHwDevice->load_sound_model(mHwDevice, sound_model,
+    status_t status = mHalInterface->loadSoundModel(sound_model,
                                                   SoundTriggerHwService::soundModelCallback,
                                                   this, handle);
 
@@ -601,6 +588,9 @@
 
 status_t SoundTriggerHwService::Module::unloadSoundModel_l(sound_model_handle_t handle)
 {
+    if (mHalInterface == 0) {
+        return NO_INIT;
+    }
     ssize_t index = mModels.indexOfKey(handle);
     if (index < 0) {
         return BAD_VALUE;
@@ -608,17 +598,20 @@
     sp<Model> model = mModels.valueAt(index);
     mModels.removeItem(handle);
     if (model->mState == Model::STATE_ACTIVE) {
-        mHwDevice->stop_recognition(mHwDevice, model->mHandle);
+        mHalInterface->stopRecognition(model->mHandle);
         model->mState = Model::STATE_IDLE;
     }
     AudioSystem::releaseSoundTriggerSession(model->mCaptureSession);
-    return mHwDevice->unload_sound_model(mHwDevice, handle);
+    return mHalInterface->unloadSoundModel(handle);
 }
 
 status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle,
                                  const sp<IMemory>& dataMemory)
 {
     ALOGV("startRecognition() model handle %d", handle);
+    if (mHalInterface == 0) {
+        return NO_INIT;
+    }
     if (!captureHotwordAllowed()) {
         return PERMISSION_DENIED;
     }
@@ -657,7 +650,7 @@
     //TODO: get capture handle and device from audio policy service
     config->capture_handle = model->mCaptureIOHandle;
     config->capture_device = model->mCaptureDevice;
-    status_t status = mHwDevice->start_recognition(mHwDevice, handle, config,
+    status_t status = mHalInterface->startRecognition(handle, config,
                                         SoundTriggerHwService::recognitionCallback,
                                         this);
 
@@ -672,6 +665,9 @@
 status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle)
 {
     ALOGV("stopRecognition() model handle %d", handle);
+    if (mHalInterface == 0) {
+        return NO_INIT;
+    }
     if (!captureHotwordAllowed()) {
         return PERMISSION_DENIED;
     }
@@ -685,7 +681,7 @@
     if (model->mState != Model::STATE_ACTIVE) {
         return INVALID_OPERATION;
     }
-    mHwDevice->stop_recognition(mHwDevice, handle);
+    mHalInterface->stopRecognition(handle);
     model->mState = Model::STATE_IDLE;
     return NO_ERROR;
 }
@@ -808,18 +804,13 @@
         }
 
         const bool supports_stop_all =
-            (mHwDevice->common.version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_1 &&
-             mHwDevice->stop_all_recognitions);
-
-        if (supports_stop_all) {
-            mHwDevice->stop_all_recognitions(mHwDevice);
-        }
+                (mHalInterface != 0) && (mHalInterface->stopAllRecognitions() == ENOSYS);
 
         for (size_t i = 0; i < mModels.size(); i++) {
             sp<Model> model = mModels.valueAt(i);
             if (model->mState == Model::STATE_ACTIVE) {
-                if (!supports_stop_all) {
-                    mHwDevice->stop_recognition(mHwDevice, model->mHandle);
+                if (mHalInterface != 0 && !supports_stop_all) {
+                    mHalInterface->stopRecognition(model->mHandle);
                 }
                 // keep model in ACTIVE state so that event is processed by onCallbackEvent()
                 if (model->mType == SOUND_MODEL_TYPE_KEYPHRASE) {
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
index 13a577a..7f7d0cc 100644
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -26,7 +26,7 @@
 #include <soundtrigger/ISoundTrigger.h>
 #include <soundtrigger/ISoundTriggerClient.h>
 #include <system/sound_trigger.h>
-#include <hardware/sound_trigger.h>
+#include "SoundTriggerHalInterface.h"
 
 namespace android {
 
@@ -103,7 +103,7 @@
     public:
 
        Module(const sp<SoundTriggerHwService>& service,
-              sound_trigger_hw_device* hwDevice,
+              const sp<SoundTriggerHalInterface>& halInterface,
               sound_trigger_module_descriptor descriptor,
               const sp<ISoundTriggerClient>& client);
 
@@ -123,7 +123,6 @@
        virtual status_t dump(int fd, const Vector<String16>& args);
 
 
-       sound_trigger_hw_device *hwDevice() const { return mHwDevice; }
        struct sound_trigger_module_descriptor descriptor() { return mDescriptor; }
        void setClient(const sp<ISoundTriggerClient>& client) { mClient = client; }
        void clearClient() { mClient.clear(); }
@@ -146,7 +145,7 @@
 
         Mutex                                  mLock;
         wp<SoundTriggerHwService>              mService;
-        struct sound_trigger_hw_device*        mHwDevice;
+        sp<SoundTriggerHalInterface>           mHalInterface;
         struct sound_trigger_module_descriptor mDescriptor;
         sp<ISoundTriggerClient>                mClient;
         DefaultKeyedVector< sound_model_handle_t, sp<Model> >     mModels;