QCamera2: Syncs snapshot done state events

- Snapshot done events have to be processed
  in synchronous fashion. If this is not the
  case, then a race condition can occur between
  camera client which receives a data callback
  and tries to trigger another capture and the
  state machine, which has yet to begin processing
  the queued snapshot done event.

Change-Id: Id0acd7e58fa360413ab4f76605b821903ba24277
diff --git a/QCamera2/HAL/QCamera2HWI.cpp b/QCamera2/HAL/QCamera2HWI.cpp
index 8cf8079..4bdae00 100644
--- a/QCamera2/HAL/QCamera2HWI.cpp
+++ b/QCamera2/HAL/QCamera2HWI.cpp
@@ -944,6 +944,10 @@
     pthread_cond_init(&m_cond, NULL);
     memset(&m_apiResult, 0, sizeof(qcamera_api_result_t));
 
+    pthread_mutex_init(&m_evtLock, NULL);
+    pthread_cond_init(&m_evtCond, NULL);
+    memset(&m_evtResult, 0, sizeof(qcamera_api_result_t));
+
     memset(m_channels, 0, sizeof(m_channels));
 
 #ifdef HAS_MULTIMEDIA_HINTS
@@ -968,6 +972,8 @@
     closeCamera();
     pthread_mutex_destroy(&m_lock);
     pthread_cond_destroy(&m_cond);
+    pthread_mutex_destroy(&m_evtLock);
+    pthread_cond_destroy(&m_evtCond);
 }
 
 /*===========================================================================
@@ -2292,6 +2298,37 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : processSyncEvt
+ *
+ * DESCRIPTION: process synchronous Evt from backend
+ *
+ * PARAMETERS :
+ *   @evt         : event type to be processed
+ *   @evt_payload : ptr to event payload if any
+ *
+ * RETURN     : int32_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int QCamera2HardwareInterface::processSyncEvt(qcamera_sm_evt_enum_t evt, void *evt_payload)
+{
+    int rc = NO_ERROR;
+
+    pthread_mutex_lock(&m_evtLock);
+    rc =  processEvt(evt, evt_payload);
+    if (rc == NO_ERROR) {
+        memset(&m_evtResult, 0, sizeof(qcamera_api_result_t));
+        while (m_evtResult.request_api != evt) {
+            pthread_cond_wait(&m_evtCond, &m_evtLock);
+        }
+        rc =  m_evtResult.status;
+    }
+    pthread_mutex_unlock(&m_evtLock);
+
+    return rc;
+}
+
+/*===========================================================================
  * FUNCTION   : evtHandle
  *
  * DESCRIPTION: Function registerd to mm-camera-interface to handle backend events
@@ -2623,6 +2660,24 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : signalEvtResult
+ *
+ * DESCRIPTION: signal condition variable that certain event was processed
+ *
+ * PARAMETERS :
+ *   @result  : Event result
+ *
+ * RETURN     : none
+ *==========================================================================*/
+void QCamera2HardwareInterface::signalEvtResult(qcamera_api_result_t *result)
+{
+    pthread_mutex_lock(&m_evtLock);
+    m_evtResult = *result;
+    pthread_cond_signal(&m_evtCond);
+    pthread_mutex_unlock(&m_evtLock);
+}
+
+/*===========================================================================
  * FUNCTION   : addStreamToChannel
  *
  * DESCRIPTION: add a stream into a channel
diff --git a/QCamera2/HAL/QCamera2HWI.h b/QCamera2/HAL/QCamera2HWI.h
index a1b217d..537929e 100644
--- a/QCamera2/HAL/QCamera2HWI.h
+++ b/QCamera2/HAL/QCamera2HWI.h
@@ -259,10 +259,12 @@
 
     int processAPI(qcamera_sm_evt_enum_t api, void *api_payload);
     int processEvt(qcamera_sm_evt_enum_t evt, void *evt_payload);
+    int processSyncEvt(qcamera_sm_evt_enum_t evt, void *evt_payload);
     void lockAPI();
     void waitAPIResult(qcamera_sm_evt_enum_t api_evt);
     void unlockAPI();
     void signalAPIResult(qcamera_api_result_t *result);
+    void signalEvtResult(qcamera_api_result_t *result);
 
     int updateThermalLevel(qcamera_thermal_level_enum_t level);
 
@@ -403,6 +405,10 @@
     pthread_cond_t m_cond;
     qcamera_api_result_t m_apiResult;
 
+    pthread_mutex_t m_evtLock;
+    pthread_cond_t m_evtCond;
+    qcamera_api_result_t m_evtResult;
+
     QCameraChannel *m_channels[QCAMERA_CH_TYPE_MAX]; // array holding channel ptr
 
     bool m_bShutterSoundPlayed;         // if shutter sound had been played
diff --git a/QCamera2/HAL/QCamera2HWICallbacks.cpp b/QCamera2/HAL/QCamera2HWICallbacks.cpp
index 5e30eb8..7f060ac 100644
--- a/QCamera2/HAL/QCamera2HWICallbacks.cpp
+++ b/QCamera2/HAL/QCamera2HWICallbacks.cpp
@@ -1128,18 +1128,18 @@
                         case QCAMERA_DATA_SNAPSHOT_CALLBACK:
                             {
                                 if (TRUE == isSnapshotActive && pme->mDataCb ) {
+                                    numOfSnapshotRcvd++;
+                                    if (numOfSnapshotExpected > 0 &&
+                                        numOfSnapshotExpected == numOfSnapshotRcvd) {
+                                        // notify HWI that snapshot is done
+                                        pme->mParent->processSyncEvt(QCAMERA_SM_EVT_SNAPSHOT_DONE,
+                                                                     NULL);
+                                    }
                                     pme->mDataCb(cb->msg_type,
                                                  cb->data,
                                                  cb->index,
                                                  cb->metadata,
                                                  pme->mCallbackCookie);
-                                    numOfSnapshotRcvd++;
-                                    if (numOfSnapshotExpected > 0 &&
-                                        numOfSnapshotExpected == numOfSnapshotRcvd) {
-                                        // notify HWI that snapshot is done
-                                        pme->mParent->processEvt(QCAMERA_SM_EVT_SNAPSHOT_DONE,
-                                                                 NULL);
-                                    }
                                 }
                             }
                             break;
diff --git a/QCamera2/HAL/QCameraStateMachine.cpp b/QCamera2/HAL/QCameraStateMachine.cpp
index 3fc050d..075e93e 100644
--- a/QCamera2/HAL/QCameraStateMachine.cpp
+++ b/QCamera2/HAL/QCameraStateMachine.cpp
@@ -1506,6 +1506,10 @@
         {
             rc = m_parent->cancelPicture();
             m_state = QCAMERA_SM_STATE_PREVIEW_STOPPED;
+            result.status = rc;
+            result.request_api = evt;
+            result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
+            m_parent->signalEvtResult(&result);
         }
         break;
     case QCAMERA_SM_EVT_THERMAL_NOTIFY:
@@ -2100,6 +2104,10 @@
         {
             rc = m_parent->cancelLiveSnapshot();
             m_state = QCAMERA_SM_STATE_RECORDING;
+            result.status = rc;
+            result.request_api = evt;
+            result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
+            m_parent->signalEvtResult(&result);
         }
         break;
     case QCAMERA_SM_EVT_THERMAL_NOTIFY:
@@ -2424,6 +2432,10 @@
                 rc = m_parent->cancelLiveSnapshot();
             }
             m_state = QCAMERA_SM_STATE_PREVIEWING;
+            result.status = rc;
+            result.request_api = evt;
+            result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
+            m_parent->signalEvtResult(&result);
         }
         break;
     case QCAMERA_SM_EVT_THERMAL_NOTIFY: