merge in mnc-dr-release history after reset to mnc-dr-dev
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
index e083315..7c5093e 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
@@ -38,10 +38,10 @@
 
 /** Function and structure definitions to keep code similar for each codec */
 #define ivdec_api_function              ih264d_api_function
-#define ivdext_init_ip_t                ih264d_init_ip_t
-#define ivdext_init_op_t                ih264d_init_op_t
-#define ivdext_fill_mem_rec_ip_t        ih264d_fill_mem_rec_ip_t
-#define ivdext_fill_mem_rec_op_t        ih264d_fill_mem_rec_op_t
+#define ivdext_create_ip_t              ih264d_create_ip_t
+#define ivdext_create_op_t              ih264d_create_op_t
+#define ivdext_delete_ip_t              ih264d_delete_ip_t
+#define ivdext_delete_op_t              ih264d_delete_op_t
 #define ivdext_ctl_set_num_cores_ip_t   ih264d_ctl_set_num_cores_ip_t
 #define ivdext_ctl_set_num_cores_op_t   ih264d_ctl_set_num_cores_op_t
 
@@ -115,15 +115,12 @@
             320 /* width */, 240 /* height */, callbacks,
             appData, component),
       mCodecCtx(NULL),
-      mMemRecords(NULL),
       mFlushOutBuffer(NULL),
       mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
       mIvColorFormat(IV_YUV_420P),
-      mNewWidth(mWidth),
-      mNewHeight(mHeight),
-      mNewLevel(0),
       mChangingResolution(false),
-      mSignalledError(false) {
+      mSignalledError(false),
+      mStride(mWidth){
     initPorts(
             kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE);
 
@@ -132,14 +129,23 @@
     // If input dump is enabled, then open create an empty file
     GENERATE_FILE_NAMES();
     CREATE_DUMP_FILE(mInFile);
-
-    CHECK_EQ(initDecoder(mWidth, mHeight), (status_t)OK);
 }
 
 SoftAVC::~SoftAVC() {
     CHECK_EQ(deInitDecoder(), (status_t)OK);
 }
 
+static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
+    UNUSED(ctxt);
+    return memalign(alignment, size);
+}
+
+static void ivd_aligned_free(void *ctxt, void *buf) {
+    UNUSED(ctxt);
+    free(buf);
+    return;
+}
+
 static size_t GetCPUCoreCount() {
     long cpuCoreCount = 1;
 #if defined(_SC_NPROCESSORS_ONLN)
@@ -149,7 +155,7 @@
     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
 #endif
     CHECK(cpuCoreCount >= 1);
-    ALOGD("Number of CPU cores: %ld", cpuCoreCount);
+    ALOGV("Number of CPU cores: %ld", cpuCoreCount);
     return (size_t)cpuCoreCount;
 }
 
@@ -235,12 +241,10 @@
     }
     mSignalledError = false;
 
-    /* Set the run-time (dynamic) parameters */
-    setParams(outputBufferWidth());
-
     /* Set number of cores/threads to be used by the codec */
     setNumCores();
 
+    mStride = 0;
     return OK;
 }
 
@@ -287,160 +291,41 @@
     return OK;
 }
 
-status_t SoftAVC::initDecoder(uint32_t width, uint32_t height) {
+status_t SoftAVC::initDecoder() {
     IV_API_CALL_STATUS_T status;
 
-    UWORD32 u4_num_reorder_frames;
-    UWORD32 u4_num_ref_frames;
-    UWORD32 u4_share_disp_buf;
-    WORD32 i4_level;
-
     mNumCores = GetCPUCoreCount();
     mCodecCtx = NULL;
 
-    /* Initialize number of ref and reorder modes (for H264) */
-    u4_num_reorder_frames = 16;
-    u4_num_ref_frames = 16;
-    u4_share_disp_buf = 0;
-
-    uint32_t displayStride = mIsAdaptive ? mAdaptiveMaxWidth : width;
-    uint32_t displayHeight = mIsAdaptive ? mAdaptiveMaxHeight : height;
-    uint32_t displaySizeY = displayStride * displayHeight;
-
-    if(mNewLevel == 0){
-        if (displaySizeY > (1920 * 1088)) {
-            i4_level = 50;
-        } else if (displaySizeY > (1280 * 720)) {
-            i4_level = 40;
-        } else if (displaySizeY > (720 * 576)) {
-            i4_level = 31;
-        } else if (displaySizeY > (624 * 320)) {
-            i4_level = 30;
-        } else if (displaySizeY > (352 * 288)) {
-            i4_level = 21;
-        } else {
-            i4_level = 20;
-        }
-    } else {
-        i4_level = mNewLevel;
-    }
-
-    {
-        iv_num_mem_rec_ip_t s_num_mem_rec_ip;
-        iv_num_mem_rec_op_t s_num_mem_rec_op;
-
-        s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip);
-        s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op);
-        s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
-
-        ALOGV("Get number of mem records");
-        status = ivdec_api_function(
-                mCodecCtx, (void *)&s_num_mem_rec_ip, (void *)&s_num_mem_rec_op);
-        if (IV_SUCCESS != status) {
-            ALOGE("Error in getting mem records: 0x%x",
-                    s_num_mem_rec_op.u4_error_code);
-            return UNKNOWN_ERROR;
-        }
-
-        mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
-    }
-
-    mMemRecords = (iv_mem_rec_t *)ivd_aligned_malloc(
-            128, mNumMemRecords * sizeof(iv_mem_rec_t));
-    if (mMemRecords == NULL) {
-        ALOGE("Allocation failure");
-        return NO_MEMORY;
-    }
-
-    memset(mMemRecords, 0, mNumMemRecords * sizeof(iv_mem_rec_t));
-
-    {
-        size_t i;
-        ivdext_fill_mem_rec_ip_t s_fill_mem_ip;
-        ivdext_fill_mem_rec_op_t s_fill_mem_op;
-        iv_mem_rec_t *ps_mem_rec;
-
-        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
-            sizeof(ivdext_fill_mem_rec_ip_t);
-        s_fill_mem_ip.i4_level = i4_level;
-        s_fill_mem_ip.u4_num_reorder_frames = u4_num_reorder_frames;
-        s_fill_mem_ip.u4_num_ref_frames = u4_num_ref_frames;
-        s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf;
-        s_fill_mem_ip.u4_num_extra_disp_buf = 0;
-        s_fill_mem_ip.e_output_format = mIvColorFormat;
-
-        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
-        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
-        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = displayStride;
-        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = displayHeight;
-        s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size =
-            sizeof(ivdext_fill_mem_rec_op_t);
-
-        ps_mem_rec = mMemRecords;
-        for (i = 0; i < mNumMemRecords; i++) {
-            ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
-        }
-
-        status = ivdec_api_function(
-                mCodecCtx, (void *)&s_fill_mem_ip, (void *)&s_fill_mem_op);
-
-        if (IV_SUCCESS != status) {
-            ALOGE("Error in filling mem records: 0x%x",
-                    s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
-            return UNKNOWN_ERROR;
-        }
-        mNumMemRecords =
-            s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled;
-
-        ps_mem_rec = mMemRecords;
-
-        for (i = 0; i < mNumMemRecords; i++) {
-            ps_mem_rec->pv_base = ivd_aligned_malloc(
-                    ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
-            if (ps_mem_rec->pv_base == NULL) {
-                ALOGE("Allocation failure for memory record #%zu of size %u",
-                        i, ps_mem_rec->u4_mem_size);
-                status = IV_FAIL;
-                return NO_MEMORY;
-            }
-
-            ps_mem_rec++;
-        }
-    }
+    mStride = outputBufferWidth();
 
     /* Initialize the decoder */
     {
-        ivdext_init_ip_t s_init_ip;
-        ivdext_init_op_t s_init_op;
+        ivdext_create_ip_t s_create_ip;
+        ivdext_create_op_t s_create_op;
 
         void *dec_fxns = (void *)ivdec_api_function;
 
-        s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
-        s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
-        s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
-        s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = displayStride;
-        s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = displayHeight;
+        s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
+        s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
+        s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
+        s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t);
+        s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat;
+        s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
+        s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
+        s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
 
-        s_init_ip.i4_level = i4_level;
-        s_init_ip.u4_num_reorder_frames = u4_num_reorder_frames;
-        s_init_ip.u4_num_ref_frames = u4_num_ref_frames;
-        s_init_ip.u4_share_disp_buf = u4_share_disp_buf;
-        s_init_ip.u4_num_extra_disp_buf = 0;
+        status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
 
-        s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op);
-
-        s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
-        s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat;
-
-        mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base;
+        mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
         mCodecCtx->pv_fxns = dec_fxns;
         mCodecCtx->u4_size = sizeof(iv_obj_t);
 
-        status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, (void *)&s_init_op);
         if (status != IV_SUCCESS) {
+            ALOGE("Error in create: 0x%x",
+                    s_create_op.s_ivd_create_op_t.u4_error_code);
+            deInitDecoder();
             mCodecCtx = NULL;
-            ALOGE("Error in init: 0x%x",
-                    s_init_op.s_ivd_init_op_t.u4_error_code);
             return UNKNOWN_ERROR;
         }
     }
@@ -449,7 +334,7 @@
     resetPlugin();
 
     /* Set the run time (dynamic) parameters */
-    setParams(displayStride);
+    setParams(mStride);
 
     /* Set number of cores/threads to be used by the codec */
     setNumCores();
@@ -457,61 +342,37 @@
     /* Get codec version */
     logVersion();
 
-    /* Allocate internal picture buffer */
-    uint32_t bufferSize = displaySizeY * 3 / 2;
-    mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, bufferSize);
-    if (NULL == mFlushOutBuffer) {
-        ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize);
-        return NO_MEMORY;
-    }
-
-    mInitNeeded = false;
     mFlushNeeded = false;
     return OK;
 }
 
 status_t SoftAVC::deInitDecoder() {
     size_t i;
+    IV_API_CALL_STATUS_T status;
 
-    if (mMemRecords) {
-        iv_mem_rec_t *ps_mem_rec;
+    if (mCodecCtx) {
+        ivdext_delete_ip_t s_delete_ip;
+        ivdext_delete_op_t s_delete_op;
 
-        ps_mem_rec = mMemRecords;
-        for (i = 0; i < mNumMemRecords; i++) {
-            if (ps_mem_rec->pv_base) {
-                ivd_aligned_free(ps_mem_rec->pv_base);
-            }
-            ps_mem_rec++;
+        s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t);
+        s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;
+
+        s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t);
+
+        status = ivdec_api_function(mCodecCtx, (void *)&s_delete_ip, (void *)&s_delete_op);
+        if (status != IV_SUCCESS) {
+            ALOGE("Error in delete: 0x%x",
+                    s_delete_op.s_ivd_delete_op_t.u4_error_code);
+            return UNKNOWN_ERROR;
         }
-        ivd_aligned_free(mMemRecords);
-        mMemRecords = NULL;
     }
 
-    if (mFlushOutBuffer) {
-        ivd_aligned_free(mFlushOutBuffer);
-        mFlushOutBuffer = NULL;
-    }
 
-    mInitNeeded = true;
     mChangingResolution = false;
 
     return OK;
 }
 
-status_t SoftAVC::reInitDecoder(uint32_t width, uint32_t height) {
-    status_t ret;
-
-    deInitDecoder();
-
-    ret = initDecoder(width, height);
-    if (OK != ret) {
-        ALOGE("Create failure");
-        deInitDecoder();
-        return NO_MEMORY;
-    }
-    return OK;
-}
-
 void SoftAVC::onReset() {
     SoftVideoDecoderOMXComponent::onReset();
 
@@ -520,23 +381,6 @@
     resetPlugin();
 }
 
-OMX_ERRORTYPE SoftAVC::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) {
-    const uint32_t oldWidth = mWidth;
-    const uint32_t oldHeight = mHeight;
-    OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
-    if (mWidth != oldWidth || mHeight != oldHeight) {
-        mNewWidth = mWidth;
-        mNewHeight = mHeight;
-        status_t err = reInitDecoder(mNewWidth, mNewHeight);
-        if (err != OK) {
-            notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL);
-            mSignalledError = true;
-            return OMX_ErrorUnsupportedSetting;
-        }
-    }
-    return ret;
-}
-
 void SoftAVC::setDecodeArgs(
         ivd_video_decode_ip_t *ps_dec_ip,
         ivd_video_decode_op_t *ps_dec_op,
@@ -587,6 +431,17 @@
     if (kOutputPortIndex == portIndex) {
         setFlushMode();
 
+        /* Allocate a picture buffer to flushed data */
+        uint32_t displayStride = outputBufferWidth();
+        uint32_t displayHeight = outputBufferHeight();
+
+        uint32_t bufferSize = displayStride * displayHeight * 3 / 2;
+        mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize);
+        if (NULL == mFlushOutBuffer) {
+            ALOGE("Could not allocate flushOutputBuffer of size %zu", bufferSize);
+            return;
+        }
+
         while (true) {
             ivd_video_decode_ip_t s_dec_ip;
             ivd_video_decode_op_t s_dec_op;
@@ -601,6 +456,12 @@
                 break;
             }
         }
+
+        if (mFlushOutBuffer) {
+            free(mFlushOutBuffer);
+            mFlushOutBuffer = NULL;
+        }
+
     }
 }
 
@@ -614,6 +475,17 @@
         return;
     }
 
+    if (NULL == mCodecCtx) {
+        if (OK != initDecoder()) {
+            return;
+        }
+    }
+    if (outputBufferWidth() != mStride) {
+        /* Set the run-time (dynamic) parameters */
+        mStride = outputBufferWidth();
+        setParams(mStride);
+    }
+
     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
 
@@ -676,22 +548,6 @@
             }
         }
 
-        // When there is an init required and the decoder is not in flush mode,
-        // update output port's definition and reinitialize decoder.
-        if (mInitNeeded && !mIsInFlush) {
-            bool portWillReset = false;
-
-            status_t err = reInitDecoder(mNewWidth, mNewHeight);
-            if (err != OK) {
-                notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL);
-                mSignalledError = true;
-                return;
-            }
-
-            handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
-            return;
-        }
-
         /* Get a free slot in timestamp array to hold input timestamp */
         {
             size_t i;
@@ -726,10 +582,7 @@
             IV_API_CALL_STATUS_T status;
             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
 
-            bool unsupportedDimensions =
-                (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & 0xFF));
             bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
-            bool unsupportedLevel = (IH264D_UNSUPPORTED_LEVEL == (s_dec_op.u4_error_code & 0xFF));
 
             GETTIME(&mTimeEnd, NULL);
             /* Compute time taken for decode() */
@@ -747,46 +600,6 @@
                 mTimeStampsValid[timeStampIx] = false;
             }
 
-
-            // This is needed to handle CTS DecoderTest testCodecResetsH264WithoutSurface,
-            // which is not sending SPS/PPS after port reconfiguration and flush to the codec.
-            if (unsupportedDimensions && !mFlushNeeded) {
-                bool portWillReset = false;
-                mNewWidth = s_dec_op.u4_pic_wd;
-                mNewHeight = s_dec_op.u4_pic_ht;
-
-                status_t err = reInitDecoder(mNewWidth, mNewHeight);
-                if (err != OK) {
-                    notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL);
-                    mSignalledError = true;
-                    return;
-                }
-
-                handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
-
-                setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
-
-                ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
-                return;
-            }
-
-            if (unsupportedLevel && !mFlushNeeded) {
-
-                mNewLevel = 51;
-
-                status_t err = reInitDecoder(mNewWidth, mNewHeight);
-                if (err != OK) {
-                    notify(OMX_EventError, OMX_ErrorUnsupportedSetting, err, NULL);
-                    mSignalledError = true;
-                    return;
-                }
-
-                setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
-
-                ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
-                return;
-            }
-
             // If the decoder is in the changing resolution mode and there is no output present,
             // that means the switching is done and it's ready to reset the decoder and the plugin.
             if (mChangingResolution && !s_dec_op.u4_output_present) {
@@ -796,28 +609,11 @@
                 continue;
             }
 
-            if (unsupportedDimensions || resChanged) {
+            if (resChanged) {
                 mChangingResolution = true;
                 if (mFlushNeeded) {
                     setFlushMode();
                 }
-
-                if (unsupportedDimensions) {
-                    mNewWidth = s_dec_op.u4_pic_wd;
-                    mNewHeight = s_dec_op.u4_pic_ht;
-                    mInitNeeded = true;
-                }
-                continue;
-            }
-
-            if (unsupportedLevel) {
-
-                if (mFlushNeeded) {
-                    setFlushMode();
-                }
-
-                mNewLevel = 51;
-                mInitNeeded = true;
                 continue;
             }
 
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.h b/media/libstagefright/codecs/avcdec/SoftAVCDec.h
index 1ec8991..9dcabb4 100644
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.h
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.h
@@ -23,9 +23,6 @@
 
 namespace android {
 
-#define ivd_aligned_malloc(alignment, size) memalign(alignment, size)
-#define ivd_aligned_free(buf) free(buf)
-
 /** Number of entries in the time-stamp array */
 #define MAX_TIME_STAMPS 64
 
@@ -62,7 +59,6 @@
     virtual void onQueueFilled(OMX_U32 portIndex);
     virtual void onPortFlushCompleted(OMX_U32 portIndex);
     virtual void onReset();
-    virtual OMX_ERRORTYPE internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params);
 private:
     // Number of input and output buffers
     enum {
@@ -70,8 +66,6 @@
     };
 
     iv_obj_t *mCodecCtx;         // Codec context
-    iv_mem_rec_t *mMemRecords;   // Memory records requested by the codec
-    size_t mNumMemRecords;       // Number of memory records requested by the codec
 
     size_t mNumCores;            // Number of cores to be uesd by the codec
 
@@ -97,17 +91,15 @@
 
     bool mIsInFlush;        // codec is flush mode
     bool mReceivedEOS;      // EOS is receieved on input port
-    bool mInitNeeded;
-    uint32_t mNewWidth;
-    uint32_t mNewHeight;
-    uint32_t mNewLevel;
+
     // The input stream has changed to a different resolution, which is still supported by the
     // codec. So the codec is switching to decode the new resolution.
     bool mChangingResolution;
     bool mFlushNeeded;
     bool mSignalledError;
+    size_t mStride;
 
-    status_t initDecoder(uint32_t width, uint32_t height);
+    status_t initDecoder();
     status_t deInitDecoder();
     status_t setFlushMode();
     status_t setParams(size_t stride);
@@ -115,7 +107,7 @@
     status_t setNumCores();
     status_t resetDecoder();
     status_t resetPlugin();
-    status_t reInitDecoder(uint32_t width, uint32_t height);
+
 
     void setDecodeArgs(
             ivd_video_decode_ip_t *ps_dec_ip,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 18bcfdb..48d09ed 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -56,9 +56,21 @@
             const struct audio_port_config *srcConfig = NULL) const;
     virtual sp<AudioPort> getAudioPort() const { return mProfile; }
     void toAudioPort(struct audio_port *port) const;
+    void setPreemptedSessions(const SortedVector<audio_session_t>& sessions);
+    SortedVector<audio_session_t> getPreemptedSessions() const;
+    bool hasPreemptedSession(audio_session_t session) const;
+    void clearPreemptedSessions();
 
 private:
     audio_port_handle_t           mId;
+    // Because a preemtible capture session can preempt another one, we end up in an endless loop
+    // situation were each session is allowed to restart after being preempted,
+    // thus preempting the other one which restarts and so on.
+    // To avoid this situation, we store which audio session was preempted when
+    // a particular input started and prevent preemption of this active input by this session.
+    // We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc...
+    SortedVector<audio_session_t> mPreemptedSessions;
+
 };
 
 class AudioInputCollection :
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 937160b..626fdae 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -93,6 +93,26 @@
     port->ext.mix.latency_class = AUDIO_LATENCY_NORMAL;
 }
 
+void AudioInputDescriptor::setPreemptedSessions(const SortedVector<audio_session_t>& sessions)
+{
+    mPreemptedSessions = sessions;
+}
+
+SortedVector<audio_session_t> AudioInputDescriptor::getPreemptedSessions() const
+{
+    return mPreemptedSessions;
+}
+
+bool AudioInputDescriptor::hasPreemptedSession(audio_session_t session) const
+{
+    return (mPreemptedSessions.indexOf(session) >= 0);
+}
+
+void AudioInputDescriptor::clearPreemptedSessions()
+{
+    mPreemptedSessions.clear();
+}
+
 status_t AudioInputDescriptor::dump(int fd)
 {
     const size_t SIZE = 256;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index dfb477d..8419ed5 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1485,10 +1485,15 @@
             // If the already active input uses AUDIO_SOURCE_HOTWORD then it is closed,
             // otherwise the active input continues and the new input cannot be started.
             sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
-            if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) {
+            if ((activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) &&
+                    !activeDesc->hasPreemptedSession(session)) {
                 ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput);
-                stopInput(activeInput, activeDesc->mSessions.itemAt(0));
-                releaseInput(activeInput, activeDesc->mSessions.itemAt(0));
+                audio_session_t activeSession = activeDesc->mSessions.itemAt(0);
+                SortedVector<audio_session_t> sessions = activeDesc->getPreemptedSessions();
+                sessions.add(activeSession);
+                inputDesc->setPreemptedSessions(sessions);
+                stopInput(activeInput, activeSession);
+                releaseInput(activeInput, activeSession);
             } else {
                 ALOGE("startInput(%d) failed: other input %d already started", input, activeInput);
                 return INVALID_OPERATION;
@@ -1592,6 +1597,7 @@
         if (mInputs.activeInputsCount() == 0) {
             SoundTrigger::setCaptureState(false);
         }
+        inputDesc->clearPreemptedSessions();
     }
     return NO_ERROR;
 }
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index eefff3d..c77cc45 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -577,22 +577,28 @@
                     }
                 }
                 waitTime = INT64_MAX;
+                // release mLock before releasing strong reference on the service as
+                // AudioPolicyService destructor calls AudioCommandThread::exit() which
+                // acquires mLock.
+                mLock.unlock();
+                svc.clear();
+                mLock.lock();
             } else {
                 waitTime = mAudioCommands[0]->mTime - curTime;
                 break;
             }
         }
-        // release mLock before releasing strong reference on the service as
-        // AudioPolicyService destructor calls AudioCommandThread::exit() which acquires mLock.
-        mLock.unlock();
-        svc.clear();
-        mLock.lock();
-        if (!exitPending() && (mAudioCommands.isEmpty() || waitTime != INT64_MAX)) {
-            // release delayed commands wake lock
+
+        // release delayed commands wake lock if the queue is empty
+        if (mAudioCommands.isEmpty()) {
             release_wake_lock(mName.string());
+        }
+
+        // At this stage we have either an empty command queue or the first command in the queue
+        // has a finite delay. So unless we are exiting it is safe to wait.
+        if (!exitPending()) {
             ALOGV("AudioCommandThread() going to sleep");
             mWaitWorkCV.waitRelative(mLock, waitTime);
-            ALOGV("AudioCommandThread() waking up");
         }
     }
     // release delayed commands wake lock before quitting
@@ -1003,6 +1009,8 @@
         requestExit();
         mWaitWorkCV.signal();
     }
+    // Note that we can call it from the thread loop if all other references have been released
+    // but it will safely return WOULD_BLOCK in this case
     requestExitAndWait();
 }