Camera2 multi-client support
Enable multiple clients to establish a shared session. Once the
session is created, allow each client to independently initiate and
terminate streaming using the `startStreaming` and `stopStreaming`
APIs. Additionally, primary clients can call create captureRequest
API. Ensure that all clients can simultaneously stream the camera
images.
Flag: com.android.internal.camera.flags.camera_multi_client
Bug:265196098
API-Coverage-Bug: 377371012
Test: A session is established with a shared configuration that
supports two streams: SurfaceView and ImageReader. The Java client
can create a session utilizing the SurfaceView stream. The native
client can create a session utilizing the ImageReader stream.
The Java client initiates streaming by creating a capture request and
using the `setRepeatingRequest` method. The native client initiates
streaming using the `startStreaming` API and the ImageReader surface
to receive camera images. Also, ran camera CTS tests on these CLs to
ensure we don't introduce any regressions.
Change-Id: I6ab4e5eef094e75c9b1230ad24afe1c50133df86
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
index 58370e5..06ee714 100644
--- a/camera/ndk/NdkCameraCaptureSession.cpp
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -178,30 +178,39 @@
EXPORT
camera_status_t ACameraCaptureSessionShared_startStreaming(
- ACameraCaptureSession* /*session*/, ACameraCaptureSession_captureCallbacksV2* /*callbacks*/,
- int /*numOutputWindows*/, ANativeWindow** /*window*/,
- int* /*captureSequenceId*/) {
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_captureCallbacksV2* callbacks,
+ int numOutputWindows, ANativeWindow** windows,
+ /*optional*/int* captureSequenceId) {
ATRACE_CALL();
- // Todo: need to add implementation
- return ACAMERA_OK;
+ return startStreamingTemplate(session, callbacks, numOutputWindows, windows,
+ captureSequenceId);
}
EXPORT
camera_status_t ACameraCaptureSessionShared_logicalCamera_startStreaming(
- ACameraCaptureSession* /*session*/,
- ACameraCaptureSession_logicalCamera_captureCallbacksV2* /*callbacks*/,
- int /*numOutputWindows*/, ANativeWindow** /*windows*/,
- int* /*captureSequenceId*/) {
+ ACameraCaptureSession* session,
+ /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacksV2* callbacks,
+ int numOutputWindows, ANativeWindow** windows,
+ /*optional*/int* captureSequenceId) {
ATRACE_CALL();
- // Todo: need to add implementation
- return ACAMERA_OK;
+ return startStreamingTemplate(session, callbacks, numOutputWindows, windows,
+ captureSequenceId);
}
EXPORT
-camera_status_t ACameraCaptureSessionShared_stopStreaming(ACameraCaptureSession* /*session*/) {
+camera_status_t ACameraCaptureSessionShared_stopStreaming(ACameraCaptureSession* session) {
ATRACE_CALL();
- // Todo: need to add implementation
- return ACAMERA_OK;
+ if (session == nullptr) {
+ ALOGE("%s: Error: session is null", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (session->isClosed()) {
+ ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+ return session->stopStreaming();
}
EXPORT
diff --git a/camera/ndk/NdkCameraCaptureSession.inc b/camera/ndk/NdkCameraCaptureSession.inc
index 258e20d..3112735 100644
--- a/camera/ndk/NdkCameraCaptureSession.inc
+++ b/camera/ndk/NdkCameraCaptureSession.inc
@@ -68,3 +68,24 @@
return session->setRepeatingRequest(cbs, numRequests, requests, captureSequenceId);
}
+
+template <class CallbackType>
+camera_status_t startStreamingTemplate(ACameraCaptureSession* session,
+ /*optional*/CallbackType* callbacks,
+ int numOutputWindows, ANativeWindow** windows,
+ /*optional*/int* captureSequenceId) {
+ ATRACE_CALL();
+ if (session == nullptr || windows == nullptr || numOutputWindows < 1) {
+ ALOGE("%s: Error: invalid input: session %p, numOutputWindows %d, windows %p",
+ __FUNCTION__, session, numOutputWindows, windows);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if (session->isClosed()) {
+ ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+ if (captureSequenceId) {
+ *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+ }
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+ return session->startStreaming(callbacks, numOutputWindows, windows, captureSequenceId);
+}
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
index f2ec573..bc6b87a 100644
--- a/camera/ndk/NdkCameraDevice.cpp
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -59,6 +59,9 @@
__FUNCTION__, device, request);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
+ if (device->isSharedMode() && !device->isPrimaryClient()) {
+ return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+ }
switch (templateId) {
case TEMPLATE_PREVIEW:
case TEMPLATE_STILL_CAPTURE:
@@ -86,6 +89,9 @@
__FUNCTION__, device, request, physicalCameraIdList);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
+ if (device->isSharedMode() && !device->isPrimaryClient()) {
+ return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+ }
switch (templateId) {
case TEMPLATE_PREVIEW:
case TEMPLATE_STILL_CAPTURE:
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
index 28cc9af..a2c34e3 100644
--- a/camera/ndk/NdkCameraManager.cpp
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -227,6 +227,11 @@
__FUNCTION__, mgr, cameraId, callback, device, primaryClient);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
+ bool sharedMode;
+ camera_status_t status = mgr->isCameraDeviceSharingSupported(cameraId, &sharedMode);
+ if ((status != ACAMERA_OK) || !sharedMode) {
+ return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+ }
return mgr->openCamera(cameraId, /*sharedMode*/true, callback, device, primaryClient);
}
diff --git a/camera/ndk/impl/ACameraCaptureSession.cpp b/camera/ndk/impl/ACameraCaptureSession.cpp
index 449c0b4..bda1f40 100644
--- a/camera/ndk/impl/ACameraCaptureSession.cpp
+++ b/camera/ndk/impl/ACameraCaptureSession.cpp
@@ -96,6 +96,9 @@
camera_status_t ret;
dev->lockDeviceForSessionOps();
{
+ if (dev->isSharedMode() && !dev->isPrimaryClient()) {
+ return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+ }
Mutex::Autolock _l(mSessionLock);
ret = dev->stopRepeatingLocked();
}
@@ -103,6 +106,27 @@
return ret;
}
+camera_status_t ACameraCaptureSession::stopStreaming() {
+#ifdef __ANDROID_VNDK__
+ std::shared_ptr<acam::CameraDevice> dev = getDevicePtr();
+#else
+ sp<acam::CameraDevice> dev = getDeviceSp();
+#endif
+ if (dev == nullptr) {
+ ALOGE("Error: Device associated with session %p has been closed!", this);
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+
+ camera_status_t ret;
+ dev->lockDeviceForSessionOps();
+ {
+ Mutex::Autolock _l(mSessionLock);
+ ret = dev->stopStreamingLocked();
+ }
+ dev->unlockDevice();
+ return ret;
+}
+
camera_status_t
ACameraCaptureSession::abortCaptures() {
#ifdef __ANDROID_VNDK__
@@ -118,6 +142,9 @@
camera_status_t ret;
dev->lockDeviceForSessionOps();
{
+ if (dev->isSharedMode() && !dev->isPrimaryClient()) {
+ return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+ }
Mutex::Autolock _l(mSessionLock);
ret = dev->flushLocked(this);
}
@@ -139,6 +166,9 @@
camera_status_t ret;
dev->lockDeviceForSessionOps();
{
+ if (dev->isSharedMode()) {
+ return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+ }
Mutex::Autolock _l(mSessionLock);
ret = dev->updateOutputConfigurationLocked(output);
}
@@ -160,6 +190,9 @@
camera_status_t ret;
dev->lockDeviceForSessionOps();
{
+ if (dev->isSharedMode()) {
+ return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+ }
Mutex::Autolock _l(mSessionLock);
ret = dev->prepareLocked(window);
}
diff --git a/camera/ndk/impl/ACameraCaptureSession.h b/camera/ndk/impl/ACameraCaptureSession.h
index 0d7a2c1..eb13b96 100644
--- a/camera/ndk/impl/ACameraCaptureSession.h
+++ b/camera/ndk/impl/ACameraCaptureSession.h
@@ -150,6 +150,12 @@
ACameraDevice* getDevice();
+ template<class T>
+ camera_status_t startStreaming(/*optional*/T* callbacks,
+ int numOutputWindows, ANativeWindow** windows, /*optional*/int* captureSequenceId);
+
+ camera_status_t stopStreaming();
+
private:
friend class android::acam::CameraDevice;
diff --git a/camera/ndk/impl/ACameraCaptureSession.inc b/camera/ndk/impl/ACameraCaptureSession.inc
index da535f8..695eb37 100644
--- a/camera/ndk/impl/ACameraCaptureSession.inc
+++ b/camera/ndk/impl/ACameraCaptureSession.inc
@@ -42,6 +42,9 @@
camera_status_t ret;
dev->lockDeviceForSessionOps();
{
+ if (dev->isSharedMode() && !dev->isPrimaryClient()) {
+ return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+ }
Mutex::Autolock _l(mSessionLock);
ret = dev->setRepeatingRequestsLocked(
this, cbs, numRequests, requests, captureSequenceId);
@@ -67,9 +70,37 @@
camera_status_t ret;
dev->lockDeviceForSessionOps();
{
+ if (dev->isSharedMode() && !dev->isPrimaryClient()) {
+ return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+ }
Mutex::Autolock _l(mSessionLock);
ret = dev->captureLocked(this, cbs, numRequests, requests, captureSequenceId);
}
dev->unlockDevice();
return ret;
}
+
+template <class T>
+camera_status_t ACameraCaptureSession::startStreaming(
+ /*optional*/T* callbacks, int numOutputWindows, ANativeWindow** windows,
+ /*optional*/int* captureSequenceId) {
+#ifdef __ANDROID_VNDK__
+ std::shared_ptr<acam::CameraDevice> dev = getDevicePtr();
+#else
+ sp<acam::CameraDevice> dev = getDeviceSp();
+#endif
+ if (dev == nullptr) {
+ ALOGE("Error: Device associated with session %p has been closed!", this);
+ return ACAMERA_ERROR_SESSION_CLOSED;
+ }
+
+ camera_status_t ret;
+ dev->lockDeviceForSessionOps();
+ {
+ Mutex::Autolock _l(mSessionLock);
+ ret = dev->startStreamingLocked(this, callbacks, numOutputWindows, windows,
+ captureSequenceId);
+ }
+ dev->unlockDevice();
+ return ret;
+}
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 4d21467..704dfc1 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -272,6 +272,28 @@
}
}
+camera_status_t CameraDevice::stopStreamingLocked() {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: camera is in closed or error state %d", __FUNCTION__, ret);
+ return ret;
+ }
+ ret = stopRepeatingLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: error when trying to stop streaming %d", __FUNCTION__, ret);
+ return ret;
+ }
+ for (auto& outputTarget : mPreviewRequestOutputs) {
+ ACameraOutputTarget_free(outputTarget);
+ }
+ mPreviewRequestOutputs.clear();
+ if (mPreviewRequest) {
+ ACaptureRequest_free(mPreviewRequest);
+ mPreviewRequest = nullptr;
+ }
+ return ACAMERA_OK;
+}
+
camera_status_t CameraDevice::updateOutputConfigurationLocked(ACaptureSessionOutput *output) {
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
@@ -715,10 +737,14 @@
return ret;
}
- ret = waitUntilIdleLocked();
- if (ret != ACAMERA_OK) {
- ALOGE("Camera device %s wait until idle failed, ret %d", getId(), ret);
- return ret;
+ // If device is opened in shared mode, there can be multiple clients accessing the
+ // camera device. So do not wait for idle if the device is opened in shared mode.
+ if ((!flags::camera_multi_client()) || (!mSharedMode)) {
+ ret = waitUntilIdleLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera device %s wait until idle failed, ret %d", getId(), ret);
+ return ret;
+ }
}
// Send onReady to previous session
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index ea7d9b6..067923c 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -127,6 +127,7 @@
void setPrimaryClient(bool isPrimary) {mIsPrimaryClient = isPrimary;};
bool isPrimaryClient() {return mIsPrimaryClient;};
+ bool isSharedMode() {return mSharedMode;};
private:
friend ACameraCaptureSession;
@@ -143,6 +144,15 @@
camera_status_t waitUntilIdleLocked();
+ camera_status_t stopStreamingLocked();
+
+ template<class T>
+ camera_status_t startStreamingLocked(ACameraCaptureSession* session,
+ /*optional*/T* callbacks,
+ int numOutputWindows, ANativeWindow** windows, /*optional*/int* captureSequenceId);
+
+ ACaptureRequest* mPreviewRequest = nullptr;
+ std::vector<ACameraOutputTarget*> mPreviewRequestOutputs;
template<class T>
camera_status_t captureLocked(sp<ACameraCaptureSession> session,
@@ -476,11 +486,15 @@
mDevice->setPrimaryClient(isPrimary);
}
- inline bool isPrimaryClient() {
+ inline bool isPrimaryClient() const {
return mDevice->isPrimaryClient();
}
- private:
+ inline bool isSharedMode() const{
+ return mDevice->isSharedMode();
+ }
+
+ private:
android::sp<android::acam::CameraDevice> mDevice;
};
diff --git a/camera/ndk/impl/ACameraDevice.inc b/camera/ndk/impl/ACameraDevice.inc
index 1fc5352..7e70d39 100644
--- a/camera/ndk/impl/ACameraDevice.inc
+++ b/camera/ndk/impl/ACameraDevice.inc
@@ -126,5 +126,102 @@
return ACAMERA_OK;
}
+template<class T>
+camera_status_t CameraDevice::startStreamingLocked(ACameraCaptureSession* session,
+ /*optional*/T* callbacks, int numOutputWindows,
+ ANativeWindow** windows, /*optional*/int* captureSequenceId) {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: camera is in closed or error state %d", __FUNCTION__, ret);
+ return ret;
+ }
+ CameraMetadata rawPreviewRequest;
+ binder::Status remoteRet = mRemote->createDefaultRequest(TEMPLATE_PREVIEW, &rawPreviewRequest);
+ if (!remoteRet.isOk()) {
+ ALOGE("%s: Create capture request failed: %s", __FUNCTION__, remoteRet.toString8().c_str());
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ // ToDo: Check if the memory allocation can be freed automatically using either default_delete
+ // or ScopedAResource.
+ mPreviewRequest = new ACaptureRequest();
+ mPreviewRequest->settings = new ACameraMetadata(rawPreviewRequest.release(),
+ ACameraMetadata::ACM_REQUEST);
+ mPreviewRequest->targets = new ACameraOutputTargets();
+ for (int i = 0; i < numOutputWindows ; i++) {
+ ACameraOutputTarget* outputTarget = nullptr;
+ ret = ACameraOutputTarget_create(windows[i], &outputTarget);
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: error while ACameraOutputTarget_create %d", __FUNCTION__, ret);
+ return ret;
+ }
+ ret = ACaptureRequest_addTarget(mPreviewRequest, outputTarget);
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: error while ACaptureRequest_addTarget %d", __FUNCTION__, ret);
+ return ret;
+ }
+ mPreviewRequestOutputs.push_back(outputTarget);
+ }
+
+ sp<CaptureRequest> req;
+ ret = allocateCaptureRequest(mPreviewRequest, req);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Convert capture request to internal format failure! ret %d", ret);
+ return ret;
+ }
+ if (req->mSurfaceList.empty()) {
+ ALOGE("Capture request without output target cannot be submitted!");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ // In shared session mode, if there are other active clients streaming then
+ // stoprepeating does not actually send request to HAL to cancel the request.
+ // Cameraservice will use this call to remove this client surfaces provided in its
+ // previous streaming request. If this is the only client for the shared camera device
+ // then camerservice will ask HAL to cancel the previous repeating request.
+ ret = stopRepeatingLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
+ return ret;
+ }
+
+ hardware::camera2::utils::SubmitInfo info;
+ std::vector<int> streamIds(req->mStreamIdxList.begin(), req->mStreamIdxList.end());
+ std::vector<int> surfaceIds(req->mSurfaceIdxList.begin(), req->mSurfaceIdxList.end());
+ remoteRet = mRemote->startStreaming(streamIds, surfaceIds, &info);
+ int sequenceId = info.mRequestId;
+ int64_t lastFrameNumber = info.mLastFrameNumber;
+ if (sequenceId < 0) {
+ ALOGE("Camera %s start streaming remote failure: ret %d", getId(), sequenceId);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+
+ Vector<sp<CaptureRequest> > requestsV;
+ requestsV.push_back(req);
+ CallbackHolder cbHolder(session, requestsV, true, callbacks);
+ mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder));
+
+ // stopRepeating above should have cleanup repeating sequence id
+ if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return ACAMERA_ERROR_CAMERA_DEVICE;
+ }
+ mRepeatingSequenceId = sequenceId;
+
+ if (mIdle) {
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+ msg->setPointer(kContextKey, session->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
+ postSessionMsgAndCleanup(msg);
+ }
+ mIdle = false;
+ mBusySession = session;
+
+ if (captureSequenceId) {
+ *captureSequenceId = sequenceId;
+ }
+ return ACAMERA_OK;
+}
+
} // namespace acam
} // namespace android
diff --git a/camera/ndk/include/camera/NdkCameraCaptureSession.h b/camera/ndk/include/camera/NdkCameraCaptureSession.h
index 06e1d34..c2aae1c 100644
--- a/camera/ndk/include/camera/NdkCameraCaptureSession.h
+++ b/camera/ndk/include/camera/NdkCameraCaptureSession.h
@@ -1242,8 +1242,7 @@
* </ul>
*/
camera_status_t ACameraCaptureSessionShared_stopStreaming(
- ACameraCaptureSession *sharedSession
-) __INTRODUCED_IN(36);
+ ACameraCaptureSession* sharedSession) __INTRODUCED_IN(36);
__END_DECLS
#endif /* _NDK_CAMERA_CAPTURE_SESSION_H */
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index d3a8e0d..b65aedf 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -562,6 +562,28 @@
return ACAMERA_OK;
}
+camera_status_t CameraDevice::stopStreamingLocked() {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: camera is in closed or error state %d", __FUNCTION__, ret);
+ return ret;
+ }
+ ret = stopRepeatingLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: error when trying to stop streaming %d", __FUNCTION__, ret);
+ return ret;
+ }
+ for (auto& outputTarget : mPreviewRequestOutputs) {
+ ACameraOutputTarget_free(outputTarget);
+ }
+ mPreviewRequestOutputs.clear();
+ if (mPreviewRequest) {
+ ACaptureRequest_free(mPreviewRequest);
+ mPreviewRequest = nullptr;
+ }
+ return ACAMERA_OK;
+}
+
camera_status_t CameraDevice::flushLocked(ACameraCaptureSession* session) {
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index 6ba30bb..5d03e95 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -157,6 +157,7 @@
void stopLooperAndDisconnect();
void setPrimaryClient(bool isPrimary) {mIsPrimaryClient = isPrimary;};
bool isPrimaryClient() {return mIsPrimaryClient;};
+ bool isSharedMode() {return mSharedMode;};
private:
friend ACameraCaptureSession;
@@ -195,6 +196,13 @@
/*out*/int* captureSequenceId,
bool isRepeating);
+ camera_status_t stopStreamingLocked();
+
+ template<class T>
+ camera_status_t startStreamingLocked(ACameraCaptureSession* session,
+ /*optional*/T* callbacks,
+ int numOutputWindows, ANativeWindow** windows, /*optional*/int* captureSequenceId);
+
void addRequestSettingsMetadata(ACaptureRequest *aCaptureRequest, sp<CaptureRequest> &req);
camera_status_t updateOutputConfigurationLocked(ACaptureSessionOutput *output);
@@ -237,6 +245,8 @@
ACameraDevice* mWrapper;
bool mSharedMode;
bool mIsPrimaryClient;
+ ACaptureRequest* mPreviewRequest = nullptr;
+ std::vector<ACameraOutputTarget*> mPreviewRequestOutputs;
// stream id -> pair of (ACameraWindowType* from application, OutputConfiguration used for
// camera service)
@@ -490,9 +500,12 @@
inline void setPrimaryClient(bool isPrimary) {
mDevice->setPrimaryClient(isPrimary);
}
- inline bool isPrimaryClient() {
+ inline bool isPrimaryClient() const {
return mDevice->isPrimaryClient();
}
+ inline bool isSharedMode() const {
+ return mDevice->isSharedMode();
+ }
private:
std::shared_ptr<android::acam::CameraDevice> mDevice;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc b/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc
index 1e724eb..1f568d2 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc
+++ b/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc
@@ -147,5 +147,131 @@
return ACAMERA_OK;
}
+template<class T>
+camera_status_t CameraDevice::startStreamingLocked(ACameraCaptureSession* session,
+ /*optional*/T* callbacks, int numOutputWindows,
+ ANativeWindow** windows, /*optional*/int* captureSequenceId) {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: camera is in closed or error state %d", __FUNCTION__, ret);
+ return ret;
+ }
+ utils::AidlCameraMetadata aidlMetadata;
+ ndk::ScopedAStatus remoteRet = mRemote->createDefaultRequest(utils::TemplateId::PREVIEW,
+ &aidlMetadata);
+ if (!remoteRet.isOk()) {
+ if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ Status errStatus = static_cast<Status>(remoteRet.getServiceSpecificError());
+ ALOGE("%s: submitRequestList call failed: %s",
+ __FUNCTION__, toString(errStatus).c_str());
+ return utils::convertFromAidl(errStatus);
+ } else {
+ ALOGE("%s: Transaction error for submitRequestList call: %d", __FUNCTION__,
+ remoteRet.getExceptionCode());
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ }
+ camera_metadata_t* rawPreviewRequest;
+ utils::cloneFromAidl(aidlMetadata, &rawPreviewRequest);
+ // ToDo: Check if the memory allocation can be freed automatically using either default_delete
+ // or ScopedAResource.
+ mPreviewRequest = new ACaptureRequest();
+ mPreviewRequest->settings = new ACameraMetadata(rawPreviewRequest,
+ ACameraMetadata::ACM_REQUEST);
+ mPreviewRequest->targets = new ACameraOutputTargets();
+ for (int i = 0; i < numOutputWindows ; i++) {
+ ACameraOutputTarget* outputTarget = nullptr;
+ ret = ACameraOutputTarget_create(windows[i], &outputTarget);
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: error while ACameraOutputTarget_create %d", __FUNCTION__, ret);
+ return ret;
+ }
+ ret = ACaptureRequest_addTarget(mPreviewRequest, outputTarget);
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: error while ACaptureRequest_addTarget %d", __FUNCTION__, ret);
+ return ret;
+ }
+ mPreviewRequestOutputs.push_back(outputTarget);
+ }
+
+ std::vector<sp<CaptureRequest>> requestsV;
+ sp<CaptureRequest> req;
+ ret = allocateCaptureRequestLocked(mPreviewRequest, req);
+ // We need to call this method since after submitRequestList is called,
+ // the request metadata queue might have removed the capture request
+ // metadata. Therefore we simply add the metadata to its wrapper class,
+ // so that it can be retrieved later.
+ addRequestSettingsMetadata(mPreviewRequest, req);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Convert capture request to internal format failure! ret %d", ret);
+ return ret;
+ }
+ if (req->mCaptureRequest.streamAndWindowIds.size() == 0) {
+ ALOGE("Capture request without output target cannot be submitted!");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ requestsV.push_back(req);
+ // In shared session mode, if there are other active clients streaming then
+ // stoprepeating does not actually send request to HAL to cancel the request.
+ // Cameraservice will use this call to remove this client surfaces provided in its
+ // previous streaming request. If this is the only client for the shared camera device
+ // then camerservice will ask HAL to cancel the previous repeating request.
+ ret = stopRepeatingLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
+ return ret;
+ }
+ SubmitInfo info;
+ std::vector<int> streamIds;
+ std::vector<int> surfaceIds;
+ for (const auto& streamAndWindowId : req->mCaptureRequest.streamAndWindowIds) {
+ streamIds.push_back(streamAndWindowId.streamId);
+ surfaceIds.push_back(streamAndWindowId.windowId);
+ }
+ remoteRet = mRemote->startStreaming(streamIds, surfaceIds, &info);
+ if (!remoteRet.isOk()) {
+ if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ Status errStatus = static_cast<Status>(remoteRet.getServiceSpecificError());
+ ALOGE("%s: startStreaming call failed: %s",
+ __FUNCTION__, toString(errStatus).c_str());
+ return utils::convertFromAidl(errStatus);
+ } else {
+ ALOGE("%s: Transaction error for startStreaming call: %d", __FUNCTION__,
+ remoteRet.getExceptionCode());
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ }
+
+ int32_t sequenceId = info.requestId;
+ int64_t lastFrameNumber = info.lastFrameNumber;
+ if (sequenceId < 0) {
+ ALOGE("Camera %s submit request remote failure: ret %d", getId(), sequenceId);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ CallbackHolder cbHolder(session, requestsV, true, callbacks);
+ mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder));
+ // stopRepeating above should have cleanup repeating sequence id
+ if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return ACAMERA_ERROR_CAMERA_DEVICE;
+ }
+ mRepeatingSequenceId = sequenceId;
+
+ if (mIdle) {
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+ msg->setPointer(kContextKey, session->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
+ postSessionMsgAndCleanup(msg);
+ }
+ mIdle = false;
+ mBusySession = session;
+
+ if (captureSequenceId) {
+ *captureSequenceId = sequenceId;
+ }
+ return ACAMERA_OK;
+}
+
} // namespace acam
} // namespace android