diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp index eb599e06c4..e996e83147 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.cpp +++ b/services/camera/libcameraservice/api1/Camera2Client.cpp @@ -959,6 +959,11 @@ void Camera2Client::stopPreviewL() { case Parameters::RECORD: case Parameters::PREVIEW: syncWithDevice(); + // Due to flush a camera device sync is not a sufficient + // guarantee that the current client parameters are + // correctly applied. To resolve this wait for the current + // request id to return in the results. + waitUntilCurrentRequestIdLocked(); res = stopStream(); if (res != OK) { ALOGE("%s: Camera %d: Can't stop streaming: %s (%d)", @@ -2259,6 +2264,46 @@ int32_t Camera2Client::setAudioRestriction(int /*mode*/) { return INVALID_OPERATION; } +status_t Camera2Client::waitUntilCurrentRequestIdLocked() { + int32_t activeRequestId = mStreamingProcessor->getActiveRequestId(); + if (activeRequestId != 0) { + auto res = waitUntilRequestIdApplied(activeRequestId, + mDevice->getExpectedInFlightDuration()); + if (res == TIMED_OUT) { + ALOGE("%s: Camera %d: Timed out waiting for current request id to return in results!", + __FUNCTION__, mCameraId); + return res; + } else if (res != OK) { + ALOGE("%s: Camera %d: Error while waiting for current request id to return in results!", + __FUNCTION__, mCameraId); + return res; + } + } + + return OK; +} + +status_t Camera2Client::waitUntilRequestIdApplied(int32_t requestId, nsecs_t timeout) { + Mutex::Autolock l(mLatestRequestMutex); + while (mLatestRequestId != requestId) { + nsecs_t startTime = systemTime(); + + auto res = mLatestRequestSignal.waitRelative(mLatestRequestMutex, timeout); + if (res != OK) return res; + + timeout -= (systemTime() - startTime); + } + + return OK; +} + +void Camera2Client::notifyRequestId(int32_t requestId) { + Mutex::Autolock al(mLatestRequestMutex); + + mLatestRequestId = requestId; + mLatestRequestSignal.signal(); +} + const char* Camera2Client::kAutofocusLabel = "autofocus"; const char* Camera2Client::kTakepictureLabel = "take_picture"; diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h index 8df8d2b5cc..e79a442143 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.h +++ b/services/camera/libcameraservice/api1/Camera2Client.h @@ -123,6 +123,8 @@ public: camera2::SharedParameters& getParameters(); + void notifyRequestId(int32_t requestId); + int getPreviewStreamId() const; int getCaptureStreamId() const; int getCallbackStreamId() const; @@ -228,6 +230,12 @@ private: status_t initializeImpl(TProviderPtr providerPtr, const String8& monitorTags); bool isZslEnabledInStillTemplate(); + + mutable Mutex mLatestRequestMutex; + Condition mLatestRequestSignal; + int32_t mLatestRequestId = -1; + status_t waitUntilRequestIdApplied(int32_t requestId, nsecs_t timeout); + status_t waitUntilCurrentRequestIdLocked(); }; }; // namespace android diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp index 683e84daee..63e293a575 100644 --- a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp +++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp @@ -86,6 +86,12 @@ bool FrameProcessor::processSingleFrame(CaptureResult &frame, process3aState(frame, client); } + if (mCurrentRequestId != frame.mResultExtras.requestId) { + mCurrentRequestId = frame.mResultExtras.requestId; + + client->notifyRequestId(mCurrentRequestId); + } + return FrameProcessorBase::processSingleFrame(frame, device); } diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.h b/services/camera/libcameraservice/api1/client2/FrameProcessor.h index 8183c1284d..142b8cda83 100644 --- a/services/camera/libcameraservice/api1/client2/FrameProcessor.h +++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.h @@ -94,6 +94,7 @@ class FrameProcessor : public FrameProcessorBase { }; AlgState m3aState; + int32_t mCurrentRequestId = -1; // frame number -> pending 3A states that not all data are received yet. KeyedVector mPending3AStates; diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h index 98c1b5e971..935bc37a62 100644 --- a/services/camera/libcameraservice/common/CameraDeviceBase.h +++ b/services/camera/libcameraservice/common/CameraDeviceBase.h @@ -383,6 +383,12 @@ class CameraDeviceBase : public virtual RefBase { * drop buffers for stream of streamId. */ virtual status_t dropStreamBuffers(bool /*dropping*/, int /*streamId*/) = 0; + + /** + * Returns the maximum expected time it'll take for all currently in-flight + * requests to complete, based on their settings + */ + virtual nsecs_t getExpectedInFlightDuration() = 0; }; }; // namespace android diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index cae34ce5c4..2573b4889c 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -194,6 +194,8 @@ class Camera3Device : */ status_t dropStreamBuffers(bool dropping, int streamId) override; + nsecs_t getExpectedInFlightDuration() override; + /** * Helper functions to map between framework and HIDL values */ @@ -1110,12 +1112,6 @@ class Camera3Device : bool isStillCapture, bool isZslCapture, const SurfaceMap& outputSurfaces); - /** - * Returns the maximum expected time it'll take for all currently in-flight - * requests to complete, based on their settings - */ - nsecs_t getExpectedInFlightDuration(); - /** * Tracking for idle detection */