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: