Add multi-client support in camera2
Add support for multiple clients to access the same camera using
camera2 api. This is initial set of changes and includes all the new
API changes as well as implementation of opening the camera in shared
mode, new open callbacks, newly added characteristics and creating
shared sesion.
After the merge of these initial changes, it will be followed by
another set of changes which will include implementation of
startStreaming and stopStreaming APIs and the capability for multiple
clients to stream the camera images.
Flag: com.android.internal.camera.flags.camera_multi_client
Bug:265196098
API-Coverage-Bug: 377371012
Test: Tested that a java and native client are able to open the camera
at the same time and get the required callbacks and they are able to get
the shared session configuration using newly added characteristics.
Tested the clientaccessprioritieschanged callback occur appropriately
when new client connects/disconnects.
Change-Id: I4cd3babf538b065d635c99c695718d8f52883afc
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index ce6c2d3..6431737 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -157,6 +157,7 @@
* policy for default device context). Only virtual cameras would be exposed
* only for custom policy and only real cameras would be exposed for default
* policy.
+ * @param sharedMode Parameter specifying if the camera should be opened in shared mode.
*/
ICameraDeviceUser connectDevice(ICameraDeviceCallbacks callbacks,
@utf8InCpp String cameraId,
@@ -164,7 +165,8 @@
int targetSdkVersion,
int rotationOverride,
in AttributionSourceState clientAttribution,
- int devicePolicy);
+ int devicePolicy,
+ boolean sharedMode);
/**
* Add listener for changes to camera device and flashlight state.
diff --git a/camera/aidl/android/hardware/ICameraServiceListener.aidl b/camera/aidl/android/hardware/ICameraServiceListener.aidl
index 9c8c88a..c0fd50e 100644
--- a/camera/aidl/android/hardware/ICameraServiceListener.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceListener.aidl
@@ -105,5 +105,6 @@
* will receive such callbacks.
*/
oneway void onCameraOpened(@utf8InCpp String cameraId, @utf8InCpp String clientPackageId, int deviceId);
+ oneway void onCameraOpenedInSharedMode(@utf8InCpp String cameraId, @utf8InCpp String clientPackageId, int deviceId, boolean primaryClient);
oneway void onCameraClosed(@utf8InCpp String cameraId, int deviceId);
}
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index 58b19a3..49e9920 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -50,4 +50,15 @@
oneway void onRepeatingRequestError(in long lastFrameNumber,
in int repeatingRequestId);
oneway void onRequestQueueEmpty();
+
+ /**
+ * Notify registered clients about client shared access priority changes when the camera device
+ * has been opened in shared mode.
+ *
+ * If the client priority changes from secondary to primary, then it can now
+ * create capture request and change the capture request parameters. If client priority
+ * changes from primary to secondary, that implies that another higher priority client is also
+ * accessing the camera in shared mode and is now the primary client.
+ */
+ oneway void onClientSharedAccessPriorityChanged(boolean primaryClient);
}
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index 8e1fcc0..c1da126 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -68,6 +68,17 @@
const int CONSTRAINED_HIGH_SPEED_MODE = 1;
/**
+ * The shared operating mode for a camera device.
+ *
+ * <p>
+ * When in shared mode, the camera device can be opened and accessed by multiple applications
+ * simultaneously.
+ * </p>
+ *
+ */
+ const int SHARED_MODE = 2;
+
+ /**
* Start of custom vendor modes
*/
const int VENDOR_MODE_START = 0x8000;
@@ -194,4 +205,12 @@
*/
ICameraOfflineSession switchToOffline(in ICameraDeviceCallbacks callbacks,
in int[] offlineOutputIds);
+
+ /**
+ * Get the client status as primary or secondary when camera is opened in shared mode.
+ *
+ * @return true if this is primary client when camera is opened in shared mode.
+ * false if another higher priority client with primary access is also using the camera.
+ */
+ boolean isPrimaryClient();
}
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index daa2656..a89d7ca 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -34,6 +34,7 @@
namespace android {
const int OutputConfiguration::INVALID_ROTATION = -1;
+const int OutputConfiguration::ROTATION_0 = 0;
const int OutputConfiguration::INVALID_SET_ID = -1;
const std::vector<sp<IGraphicBufferProducer>>&
@@ -97,6 +98,10 @@
return mTimestampBase;
}
+int OutputConfiguration::getMirrorMode() const {
+ return mMirrorMode;
+}
+
int OutputConfiguration::getMirrorMode(sp<IGraphicBufferProducer> surface) const {
if (!flags::mirror_mode_shared_surfaces()) {
return mMirrorMode;
@@ -164,6 +169,29 @@
mUsage(0) {
}
+OutputConfiguration::OutputConfiguration(int surfaceType, int width, int height, int format,
+ int32_t colorSpace, int mirrorMode, bool useReadoutTimestamp, int timestampBase,
+ int dataspace, int64_t usage, int64_t streamusecase, std::string physicalCamId):
+ mRotation(ROTATION_0),
+ mSurfaceSetID(INVALID_SET_ID),
+ mSurfaceType(surfaceType),
+ mWidth(width),
+ mHeight(height),
+ mIsDeferred(false),
+ mIsShared(false),
+ mPhysicalCameraId(physicalCamId),
+ mIsMultiResolution(false),
+ mDynamicRangeProfile(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD),
+ mColorSpace(colorSpace),
+ mStreamUseCase(streamusecase),
+ mTimestampBase(timestampBase),
+ mMirrorMode(mirrorMode),
+ mUseReadoutTimestamp(useReadoutTimestamp),
+ mFormat(format),
+ mDataspace(dataspace),
+ mUsage(usage){
+}
+
OutputConfiguration::OutputConfiguration(const android::Parcel& parcel) :
mRotation(INVALID_ROTATION),
mSurfaceSetID(INVALID_SET_ID) {
diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig
index ebfd7d7..968b28f 100644
--- a/camera/camera_platform.aconfig
+++ b/camera/camera_platform.aconfig
@@ -235,3 +235,14 @@
description: "Add new feature combination query version for Baklava"
bug: "370778206"
}
+
+flag {
+ namespace: "camera_platform"
+ name: "camera_multi_client"
+ is_exported: true
+ description: "add new feature to allow multiple clients to access the camera in shared mode"
+ bug: "265196098"
+ metadata {
+ purpose: PURPOSE_FEATURE
+ }
+}
diff --git a/camera/cameraserver/manifest_android.frameworks.cameraservice.service.xml b/camera/cameraserver/manifest_android.frameworks.cameraservice.service.xml
index 5d85909..d8264df 100644
--- a/camera/cameraserver/manifest_android.frameworks.cameraservice.service.xml
+++ b/camera/cameraserver/manifest_android.frameworks.cameraservice.service.xml
@@ -11,7 +11,7 @@
<hal format="aidl">
<name>android.frameworks.cameraservice.service</name>
- <version>2</version>
+ <version>3</version>
<interface>
<name>ICameraService</name>
<instance>default</instance>
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
index 2049a31..671d065 100644
--- a/camera/include/camera/camera2/OutputConfiguration.h
+++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -33,6 +33,7 @@
class OutputConfiguration : public android::Parcelable {
public:
+ static const int ROTATION_0;
static const int INVALID_ROTATION;
static const int INVALID_SET_ID;
enum SurfaceType {
@@ -73,6 +74,7 @@
int64_t getStreamUseCase() const;
int getTimestampBase() const;
int getMirrorMode(sp<IGraphicBufferProducer> surface) const;
+ int getMirrorMode() const;
bool useReadoutTimestamp() const;
int getFormat() const;
int getDataspace() const;
@@ -107,6 +109,9 @@
int surfaceSetID = INVALID_SET_ID,
int surfaceType = SURFACE_TYPE_UNKNOWN, int width = 0,
int height = 0, bool isShared = false);
+ OutputConfiguration(int surfaceType, int width, int height, int format, int32_t colorSpace,
+ int mirrorMode, bool useReadoutTimestamp,int timestampBase, int dataspace,
+ int64_t usage, int64_t streamusecase, std::string physicalCamId);
bool operator == (const OutputConfiguration& other) const {
return ( mRotation == other.mRotation &&
@@ -211,6 +216,28 @@
bool mirrorModesEqual(const OutputConfiguration& other) const;
bool mirrorModesLessThan(const OutputConfiguration& other) const;
const std::vector<int32_t>& getMirrorModes() const {return mMirrorModeForProducers;}
+ bool sharedConfigEqual(const OutputConfiguration& other) const {
+ return (mRotation == other.mRotation &&
+ mSurfaceSetID == other.mSurfaceSetID &&
+ mSurfaceType == other.mSurfaceType &&
+ mWidth == other.mWidth &&
+ mHeight == other.mHeight &&
+ mIsDeferred == other.mIsDeferred &&
+ mIsShared == other.mIsShared &&
+ mPhysicalCameraId == other.mPhysicalCameraId &&
+ mIsMultiResolution == other.mIsMultiResolution &&
+ sensorPixelModesUsedEqual(other) &&
+ mDynamicRangeProfile == other.mDynamicRangeProfile &&
+ mColorSpace == other.mColorSpace &&
+ mStreamUseCase == other.mStreamUseCase &&
+ mTimestampBase == other.mTimestampBase &&
+ mMirrorMode == other.mMirrorMode &&
+ mUseReadoutTimestamp == other.mUseReadoutTimestamp &&
+ mFormat == other.mFormat &&
+ mDataspace == other.mDataspace &&
+ mUsage == other.mUsage);
+ }
+
private:
std::vector<sp<IGraphicBufferProducer>> mGbps;
int mRotation;
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 379c0b5..508808f 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -79,6 +79,7 @@
shared_libs: [
"android.companion.virtual.virtualdevice_aidl-cpp",
"android.companion.virtualdevice.flags-aconfig-cc",
+ "camera_platform_flags_c_lib",
"framework-permission-aidl-cpp",
"libandroid_runtime",
"libbinder",
@@ -147,8 +148,8 @@
shared_libs: [
"android.frameworks.cameraservice.common-V1-ndk",
- "android.frameworks.cameraservice.device-V2-ndk",
- "android.frameworks.cameraservice.service-V2-ndk",
+ "android.frameworks.cameraservice.device-V3-ndk",
+ "android.frameworks.cameraservice.service-V3-ndk",
"libbinder_ndk",
"libcamera_metadata",
"libcutils",
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
index 92de1e4..58370e5 100644
--- a/camera/ndk/NdkCameraCaptureSession.cpp
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -177,6 +177,34 @@
}
EXPORT
+camera_status_t ACameraCaptureSessionShared_startStreaming(
+ ACameraCaptureSession* /*session*/, ACameraCaptureSession_captureCallbacksV2* /*callbacks*/,
+ int /*numOutputWindows*/, ANativeWindow** /*window*/,
+ int* /*captureSequenceId*/) {
+ ATRACE_CALL();
+ // Todo: need to add implementation
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraCaptureSessionShared_logicalCamera_startStreaming(
+ ACameraCaptureSession* /*session*/,
+ ACameraCaptureSession_logicalCamera_captureCallbacksV2* /*callbacks*/,
+ int /*numOutputWindows*/, ANativeWindow** /*windows*/,
+ int* /*captureSequenceId*/) {
+ ATRACE_CALL();
+ // Todo: need to add implementation
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraCaptureSessionShared_stopStreaming(ACameraCaptureSession* /*session*/) {
+ ATRACE_CALL();
+ // Todo: need to add implementation
+ return ACAMERA_OK;
+}
+
+EXPORT
camera_status_t ACameraCaptureSession_updateSharedOutput(ACameraCaptureSession* session,
ACaptureSessionOutput* output) {
ATRACE_CALL();
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
index 1b3343e..28cc9af 100644
--- a/camera/ndk/NdkCameraManager.cpp
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -27,6 +27,8 @@
#include "ndk_vendor/impl/ACameraManager.h"
#else
#include "impl/ACameraManager.h"
+#include <com_android_internal_camera_flags.h>
+namespace flags = com::android::internal::camera::flags;
#endif
#include "impl/ACameraMetadata.h"
@@ -159,6 +161,23 @@
}
EXPORT
+camera_status_t ACameraManager_isCameraDeviceSharingSupported(ACameraManager *mgr,
+ const char *cameraId, bool *isSharingSupported) {
+ ATRACE_CALL();
+ #ifndef __ANDROID_VNDK__
+ if (!flags::camera_multi_client()) {
+ return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+ }
+ #endif
+ if (mgr == nullptr || cameraId == nullptr || isSharingSupported == nullptr) {
+ ALOGE("%s: invalid argument! mgr %p cameraId %p isSharingSupported %p",
+ __FUNCTION__, mgr, cameraId, isSharingSupported);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return mgr->isCameraDeviceSharingSupported(cameraId, isSharingSupported);
+}
+
+EXPORT
camera_status_t ACameraManager_getCameraCharacteristics(
ACameraManager* mgr, const char* cameraId, ACameraMetadata** chars){
ATRACE_CALL();
@@ -188,7 +207,27 @@
__FUNCTION__, mgr, cameraId, callback, device);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- return mgr->openCamera(cameraId, callback, device);
+ bool primaryClient;
+ return mgr->openCamera(cameraId, /*sharedMode*/false, callback, device, &primaryClient);
+}
+
+EXPORT
+camera_status_t ACameraManager_openSharedCamera(
+ ACameraManager* mgr, const char* cameraId, ACameraDevice_StateCallbacks* callback,
+ /*out*/ACameraDevice** device, /*out*/bool* primaryClient) {
+ ATRACE_CALL();
+ #ifndef __ANDROID_VNDK__
+ if (!flags::camera_multi_client()) {
+ return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+ }
+ #endif
+ if (mgr == nullptr || cameraId == nullptr || callback == nullptr || device == nullptr ||
+ primaryClient == nullptr) {
+ ALOGE("%s: invalid argument! mgr %p cameraId %p callback %p device %p primary %p",
+ __FUNCTION__, mgr, cameraId, callback, device, primaryClient);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return mgr->openCamera(cameraId, /*sharedMode*/true, callback, device, primaryClient);
}
#ifdef __ANDROID_VNDK__
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 1fa71f4..aed740f 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -26,6 +26,9 @@
#include "ACameraMetadata.h"
#include "ACaptureRequest.h"
#include "ACameraCaptureSession.h"
+#include <com_android_internal_camera_flags.h>
+
+namespace flags = com::android::internal::camera::flags;
ACameraDevice::~ACameraDevice() {
mDevice->stopLooperAndDisconnect();
@@ -57,12 +60,13 @@
const char* id,
ACameraDevice_StateCallbacks* cb,
sp<ACameraMetadata> chars,
- ACameraDevice* wrapper) :
+ ACameraDevice* wrapper, bool sharedMode) :
mCameraId(id),
mAppCallbacks(*cb),
mChars(chars),
mServiceCallback(new ServiceCallback(this)),
mWrapper(wrapper),
+ mSharedMode(sharedMode),
mInError(false),
mError(ACAMERA_OK),
mIdle(true),
@@ -970,6 +974,7 @@
case kWhatCaptureSeqAbort:
case kWhatCaptureBufferLost:
case kWhatPreparedCb:
+ case kWhatClientSharedAccessPriorityChanged:
ALOGV("%s: Received msg %d", __FUNCTION__, msg->what());
break;
case kWhatCleanUpSessions:
@@ -1007,6 +1012,32 @@
(*onDisconnected)(context, dev);
break;
}
+
+ case kWhatClientSharedAccessPriorityChanged:
+ {
+ if (!flags::camera_multi_client()) {
+ break;
+ }
+ ACameraDevice* dev;
+ found = msg->findPointer(kDeviceKey, (void**) &dev);
+ if (!found || dev == nullptr) {
+ ALOGE("%s: Cannot find device pointer!", __FUNCTION__);
+ return;
+ }
+ ACameraDevice_ClientSharedAccessPriorityChangedCallback
+ onClientSharedAccessPriorityChanged;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onClientSharedAccessPriorityChanged);
+ if (!found) {
+ ALOGE("%s: Cannot find onClientSharedAccessPriorityChanged!", __FUNCTION__);
+ return;
+ }
+ if (onClientSharedAccessPriorityChanged == nullptr) {
+ return;
+ }
+ (*onClientSharedAccessPriorityChanged)(context, dev, dev->isPrimaryClient());
+ break;
+ }
+
case kWhatOnError:
{
ACameraDevice* dev;
@@ -1624,6 +1655,31 @@
}
binder::Status
+CameraDevice::ServiceCallback::onClientSharedAccessPriorityChanged(bool primaryClient) {
+ ALOGV("onClientSharedAccessPriorityChanged received. primaryClient = %d", primaryClient);
+ binder::Status ret = binder::Status::ok();
+ if (!flags::camera_multi_client()) {
+ return ret;
+ }
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return ret; // device has been closed
+ }
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->isClosed() || dev->mRemote == nullptr) {
+ return ret;
+ }
+ dev->setPrimaryClient(primaryClient);
+ sp<AMessage> msg = new AMessage(kWhatClientSharedAccessPriorityChanged, dev->mHandler);
+ msg->setPointer(kContextKey, dev->mAppCallbacks.context);
+ msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
+ msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onClientSharedAccessPriorityChanged);
+ msg->post();
+
+ return binder::Status::ok();
+}
+
+binder::Status
CameraDevice::ServiceCallback::onDeviceIdle() {
ALOGV("Camera is now idle");
binder::Status ret = binder::Status::ok();
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 2b9f327..d3aed4b 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -63,7 +63,7 @@
public:
CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
sp<ACameraMetadata> chars,
- ACameraDevice* wrapper);
+ ACameraDevice* wrapper, bool sharedMode);
~CameraDevice();
inline const char* getId() const { return mCameraId.c_str(); }
@@ -98,6 +98,7 @@
binder::Status onRequestQueueEmpty() override;
binder::Status onRepeatingRequestError(int64_t lastFrameNumber,
int32_t stoppedSequenceId) override;
+ binder::Status onClientSharedAccessPriorityChanged(bool isPrimaryClient) override;
private:
const wp<CameraDevice> mDevice;
};
@@ -113,6 +114,9 @@
// Stop the looper thread and unregister the handler
void stopLooperAndDisconnect();
+ void setPrimaryClient(bool isPrimary) {mIsPrimaryClient = isPrimary;};
+ bool isPrimaryClient() {return mIsPrimaryClient;};
+
private:
friend ACameraCaptureSession;
camera_status_t checkCameraClosedOrErrorLocked() const;
@@ -186,6 +190,8 @@
const sp<ACameraMetadata> mChars; // Camera characteristics
const sp<ServiceCallback> mServiceCallback;
ACameraDevice* mWrapper;
+ bool mSharedMode;
+ bool mIsPrimaryClient;
// stream id -> pair of (ANW* from application, OutputConfiguration used for camera service)
std::map<int, std::pair<ANativeWindow*, OutputConfiguration>> mConfiguredOutputs;
@@ -227,7 +233,8 @@
kWhatCaptureBufferLost, // onCaptureBufferLost
kWhatPreparedCb, // onWindowPrepared
// Internal cleanup
- kWhatCleanUpSessions // Cleanup cached sp<ACameraCaptureSession>
+ kWhatCleanUpSessions, // Cleanup cached sp<ACameraCaptureSession>
+ kWhatClientSharedAccessPriorityChanged
};
static const char* kContextKey;
static const char* kDeviceKey;
@@ -403,8 +410,8 @@
*/
struct ACameraDevice {
ACameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
- sp<ACameraMetadata> chars) :
- mDevice(new android::acam::CameraDevice(id, cb, chars, this)) {}
+ sp<ACameraMetadata> chars, bool sharedMode) :
+ mDevice(new android::acam::CameraDevice(id, cb, chars, this, sharedMode)) {}
~ACameraDevice();
@@ -445,6 +452,14 @@
mDevice->setRemoteDevice(remote);
}
+ inline void setPrimaryClient(bool isPrimary) {
+ mDevice->setPrimaryClient(isPrimary);
+ }
+
+ inline bool isPrimaryClient() {
+ return mDevice->isPrimaryClient();
+ }
+
private:
android::sp<android::acam::CameraDevice> mDevice;
};
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 53c4489..5dddd29 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -28,9 +28,11 @@
#include <memory>
#include "ACameraDevice.h"
#include "ACameraMetadata.h"
+#include <com_android_internal_camera_flags.h>
using namespace android::acam;
namespace vd_flags = android::companion::virtualdevice::flags;
+namespace flags = com::android::internal::camera::flags;
namespace android {
namespace acam {
@@ -860,10 +862,36 @@
}
camera_status_t
-ACameraManager::openCamera(
+ACameraManager::isCameraDeviceSharingSupported(
const char* cameraId,
+ /*out*/bool* isSharingSupported) {
+ if (!flags::camera_multi_client()) {
+ return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+ }
+ sp<ACameraMetadata> spChars;
+ camera_status_t ret = getCameraCharacteristics(cameraId, &spChars);
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: cannot get camera characteristics for camera %s. err %d",
+ __FUNCTION__, cameraId, ret);
+ return ret;
+ }
+
+ ACameraMetadata* chars = spChars.get();
+ ACameraMetadata_const_entry entry;
+ ret = ACameraMetadata_getConstEntry(chars, ANDROID_SHARED_SESSION_OUTPUT_CONFIGURATIONS,
+ &entry);
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+ *isSharingSupported = (entry.count > 0) ? true : false;
+ return ACAMERA_OK;
+}
+
+camera_status_t
+ACameraManager::openCamera(
+ const char* cameraId, bool sharedMode,
ACameraDevice_StateCallbacks* callback,
- /*out*/ACameraDevice** outDevice) {
+ /*out*/ACameraDevice** outDevice, /*out*/bool* primaryClient) {
sp<ACameraMetadata> chars;
camera_status_t ret = getCameraCharacteristics(cameraId, &chars);
Mutex::Autolock _l(mLock);
@@ -873,7 +901,7 @@
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- ACameraDevice* device = new ACameraDevice(cameraId, callback, chars);
+ ACameraDevice* device = new ACameraDevice(cameraId, callback, chars, sharedMode);
sp<hardware::ICameraService> cs = mGlobalManager->getCameraService();
if (cs == nullptr) {
@@ -898,7 +926,7 @@
binder::Status serviceRet = cs->connectDevice(
callbacks, cameraId, /*oomScoreOffset*/0,
targetSdkVersion, /*rotationOverride*/hardware::ICameraService::ROTATION_OVERRIDE_NONE,
- clientAttribution, static_cast<int32_t>(mDeviceContext.policy),
+ clientAttribution, static_cast<int32_t>(mDeviceContext.policy), sharedMode,
/*out*/&deviceRemote);
if (!serviceRet.isOk()) {
@@ -942,6 +970,14 @@
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
}
device->setRemoteDevice(deviceRemote);
+ if (flags::camera_multi_client() && sharedMode) {
+ binder::Status remoteRet = deviceRemote->isPrimaryClient(primaryClient);
+ if (!remoteRet.isOk()) {
+ delete device;
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ device->setPrimaryClient(*primaryClient);
+ }
*outDevice = device;
return ACAMERA_OK;
}
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index cb7a4ff..fffe037 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -138,6 +138,10 @@
virtual binder::Status onCameraOpened(const std::string&, const std::string&, int32_t) {
return binder::Status::ok();
}
+ virtual binder::Status onCameraOpenedInSharedMode(const std::string&, const std::string&,
+ int32_t, bool) {
+ return binder::Status::ok();
+ }
virtual binder::Status onCameraClosed(const std::string&, int32_t) {
return binder::Status::ok();
}
@@ -327,16 +331,17 @@
camera_status_t getCameraCharacteristics(
const char* cameraId, android::sp<ACameraMetadata>* characteristics);
- camera_status_t openCamera(const char* cameraId,
+ camera_status_t openCamera(const char* cameraId, bool sharedMode,
ACameraDevice_StateCallbacks* callback,
- /*out*/ACameraDevice** device);
+ /*out*/ACameraDevice** device, /*out*/bool* primaryClient);
void registerAvailabilityCallback(const ACameraManager_AvailabilityCallbacks* callback);
void unregisterAvailabilityCallback(const ACameraManager_AvailabilityCallbacks* callback);
void registerExtendedAvailabilityCallback(
const ACameraManager_ExtendedAvailabilityCallbacks* callback);
void unregisterExtendedAvailabilityCallback(
const ACameraManager_ExtendedAvailabilityCallbacks* callback);
-
+ camera_status_t isCameraDeviceSharingSupported(
+ const char* cameraId, bool* isSharingSupported);
private:
enum {
kCameraIdListNotInit = -1
diff --git a/camera/ndk/include/camera/NdkCameraCaptureSession.h b/camera/ndk/include/camera/NdkCameraCaptureSession.h
index 1400121..e73222b 100644
--- a/camera/ndk/include/camera/NdkCameraCaptureSession.h
+++ b/camera/ndk/include/camera/NdkCameraCaptureSession.h
@@ -1099,6 +1099,92 @@
camera_status_t ACameraCaptureSession_prepareWindow(
ACameraCaptureSession* session,
ANativeWindow *window) __INTRODUCED_IN(34);
+
+/**
+ * Request continuous streaming of a sequence of images for the shared capture session
+ * when more than one clients can open the same camera in shared mode by calling
+ * {@link ACameraManager_openSharedCamera}. In shared session, only primary clients can create
+ * a capture request and change capture parameters. Secondary clients can only request streaming of
+ * images by calling this api {@link ACameraCaptureSessionShared_startStreaming}. Calling this api
+ * for normal sessions when {@link ACameraManager_openCamera} is used to open the camera will throw
+ * {@link ACAMERA_ERROR_INVALID_OPERATION}.
+ *
+ * <p>With this method, the camera device will continually capture images, cycling through the
+ * settings in the list of {@link ACaptureRequest} specified by the primary client. If primary
+ * client does not have ongoing repeating request, camera service will use a capture request with
+ * default capture parameters for preview template.</p>
+ *
+ * <p>To stop the continuous streaming, call {@link ACameraCaptureSessionShared_stopStreaming}.</p>
+ *
+ * <p>Calling this method will replace an existing continuous streaming request.</p>
+ *
+ * @param sharedSession the shared capture session when camera is opened in
+ * shared mode.
+ * @param callbacks the {@link ACameraCaptureSession_captureCallbacks} to be associated with this
+ * capture sequence. No capture callback will be fired if callbacks is set to NULL.
+ * @param numOutputWindows number of native windows to be used for streaming. Must be at least 1.
+ * @param windows an array of {@link ANativeWindow} to be used for streaming. Length must be at
+ * least numOutputWindows.
+ * @param captureSequenceId the capture sequence ID associated with this capture method invocation
+ * will be stored here if this argument is not NULL and the method call succeeds.
+ * When this argument is set to NULL, the capture sequence ID will not be returned.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method succeeds. captureSequenceId will be filled
+ * if it is not NULL.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if session or requests is NULL, or
+ * if numRequests < 1</li>
+ * <li>{@link ACAMERA_ERROR_SESSION_CLOSED} if the capture session has been closed</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_DISCONNECTED} if the camera device is closed</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_DEVICE} if the camera device encounters fatal error</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_SERVICE} if the camera service encounters fatal error
+ * </li>
+ * <li>{@link ACAMERA_ERROR_INVALID_OPERATION} if the session passed is not a shared
+ * session</li>
+ * <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons</li>
+ * </ul>
+ */
+camera_status_t ACameraCaptureSessionShared_startStreaming(
+ ACameraCaptureSession* sharedSession, ACameraCaptureSession_captureCallbacksV2 *callbacks,
+ int numOutputWindows, ANativeWindow **window,
+ int *captureSequenceId) __INTRODUCED_IN(36);
+
+/**
+ * This has the same functionality as ACameraCaptureSessionShared_startStreaming, with added
+ * support for logical multi-camera where the capture callbacks supports result metadata for
+ * physical cameras.
+ */
+camera_status_t ACameraCaptureSessionShared_logicalCamera_startStreaming(
+ ACameraCaptureSession* sharedSession,
+ ACameraCaptureSession_logicalCamera_captureCallbacksV2 *callbacks,
+ int numOutputWindows, ANativeWindow **windows,
+ int *captureSequenceId) __INTRODUCED_IN(36);
+
+/**
+ * Cancel any ongoing streaming started by {@link ACameraCaptureSessionShared_startStreaming}.
+ * Calling this api does not effect any streaming requests submitted by other clients who have
+ * opened the camera in shared mode. Calling this api for normal sessions when
+ * {@link ACameraManager_openCamera} is used to open the camera will throw
+ * {@link ACAMERA_ERROR_INVALID_OPERATION}.
+ *
+ * @param sharedSession the capture session of interest
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if session is NULL.</li>
+ * <li>{@link ACAMERA_ERROR_SESSION_CLOSED} if the capture session has been closed</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_DISCONNECTED} if the camera device is closed</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_DEVICE} if the camera device encounters fatal error</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_SERVICE} if the camera service encounters fatal error
+ * </li>
+ * <li>{@link ACAMERA_ERROR_INVALID_OPERATION} if the session passed is not a shared
+ * session</li>
+ * <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons</li>
+ * </ul>
+ */
+camera_status_t ACameraCaptureSessionShared_stopStreaming(
+ ACameraCaptureSession *sharedSession
+) __INTRODUCED_IN(36);
__END_DECLS
#endif /* _NDK_CAMERA_CAPTURE_SESSION_H */
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
index fbd0ee1..8c7eb1f 100644
--- a/camera/ndk/include/camera/NdkCameraDevice.h
+++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -125,6 +125,18 @@
typedef void (*ACameraDevice_ErrorStateCallback)(void* context, ACameraDevice* device, int error);
/**
+ * Client access priorities changed callbacks to be used in {@link ACameraDevice_StateCallbacks}
+ * when camera is opened in shared mode.
+ *
+ * @param context The optional context in {@link ACameraDevice_StateCallbacks} will be passed to
+ * this callback.
+ * @param device The {@link ACameraDevice} whose access priorities has been changed.
+ * @param isPrimaryClient whether the client is primary client.
+ */
+typedef void (*ACameraDevice_ClientSharedAccessPriorityChangedCallback)(void* context,
+ ACameraDevice* device, bool isPrimaryClient);
+
+/**
* Applications' callbacks for camera device state changes, register with
* {@link ACameraManager_openCamera}.
*/
@@ -163,6 +175,17 @@
*
*/
ACameraDevice_ErrorStateCallback onError;
+
+ /**
+ * Notify registered clients about client shared access priority changes when the camera device
+ * has been opened in shared mode.
+ *
+ * If the client priority changes from secondary to primary, then it can now
+ * create capture request and change the capture request parameters. If client priority
+ * changes from primary to secondary, that implies that another higher priority client is also
+ * accessing the camera in shared mode and is now the primary client.
+ */
+ ACameraDevice_ClientSharedAccessPriorityChangedCallback onClientSharedAccessPriorityChanged;
} ACameraDevice_StateCallbacks;
/**
@@ -671,7 +694,9 @@
* <li>{@link ACAMERA_OK} if the method call succeeds. The created capture session will be
* filled in session argument.</li>
* <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if any of device, outputs, callbacks or
- * session is NULL.</li>
+ * session is NULL or if the outputs does not match the predefined
+ * shared session configuration when camera is opened in shared mode.
+ * </li>
* <li>{@link ACAMERA_ERROR_CAMERA_DISCONNECTED} if the camera device is closed.</li>
* <li>{@link ACAMERA_ERROR_CAMERA_DEVICE} if the camera device encounters fatal error.</li>
* <li>{@link ACAMERA_ERROR_CAMERA_SERVICE} if the camera service encounters fatal error.</li>
diff --git a/camera/ndk/include/camera/NdkCameraManager.h b/camera/ndk/include/camera/NdkCameraManager.h
index b4f3bf1..a9b0174 100644
--- a/camera/ndk/include/camera/NdkCameraManager.h
+++ b/camera/ndk/include/camera/NdkCameraManager.h
@@ -293,6 +293,46 @@
/*out*/ACameraDevice** device) __INTRODUCED_IN(24);
/**
+ * Open a shared connection to a camera with the given ID. The opened camera device will be
+ * returned in the `device` parameter. The behavior of this method matches that of
+ * {@link ACameraManager_openCamera(ACameraManager*, const char*, ACameraDevice_StateCallbacks*,
+ * ACameraDevice**)} except that it opens the camera in shared mode so that more
+ * than one client can access the camera at the same time.
+ *
+ * <p>Processes need to have android.permission.SYSTEM_CAMERA in addition to
+ * android.permission.CAMERA in order to connect to this camera device in shared
+ * mode.</p>
+ *
+ * @param manager the {@link ACameraManager} of interest.
+ * @param cameraId the ID string of the camera device to be opened.
+ * @param callback the {@link ACameraDevice_StateCallbacks} associated with the opened camera
+ * device.
+ * @param device the opened {@link ACameraDevice} will be filled here if the method call succeeds.
+ * @param primaryClient will return as true if the client is primaryClient.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if manager, cameraId, callback, or device
+ * is NULL, or cameraId does not match any camera devices connected.</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_DISCONNECTED} if connection to camera service fails.</li>
+ * <li>{@link ACAMERA_ERROR_NOT_ENOUGH_MEMORY} if allocating memory fails.</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_IN_USE} if camera device is being used by a higher
+ * priority camera API client.</li>
+ * <li>{@link ACAMERA_ERROR_MAX_CAMERA_IN_USE} if the system-wide limit for number of open
+ * cameras or camera resources has been reached, and more camera devices cannot be
+ * opened until previous instances are closed.</li>
+ * <li>{@link ACAMERA_ERROR_CAMERA_DISABLED} if the camera is disabled due to a device
+ * policy, and cannot be opened.</li>
+ * <li>{@link ACAMERA_ERROR_PERMISSION_DENIED} if the application does not have permission
+ * to open camera.</li>
+ * <li>{@link ACAMERA_ERROR_UNKNOWN} if the method fails for some other reasons.</li></ul>
+ */
+camera_status_t ACameraManager_openSharedCamera(
+ ACameraManager* manager, const char* cameraId,
+ ACameraDevice_StateCallbacks* callback,
+ /*out*/ACameraDevice** device,/*out*/bool* isPrimaryClient) __INTRODUCED_IN(36);
+
+/**
* Definition of camera access permission change callback.
*
* <p>Notification that camera access priorities have changed and the camera may
@@ -397,6 +437,27 @@
ACameraManager* manager,
const ACameraManager_ExtendedAvailabilityCallbacks* callback) __INTRODUCED_IN(29);
+
+/**
+ * Checks if a camera can be opened in shared mode by multiple clients.
+ *
+ * @param manager the {@link ACameraManager} of interest.
+ * @param cameraId the ID string of the camera device of interest.
+ * @param isSharingSupported output will be filled here if the method succeeds.
+ * This will be true if camera can be opened in shared mode, false
+ * otherwise.
+ *
+ * @return <ul>
+ * <li>{@link ACAMERA_OK} if the method call succeeds.</li>
+ * <li>{@link ACAMERA_ERROR_INVALID_PARAMETER} if any parameter is not
+ * valid.</li>
+ * </ul>
+ */
+camera_status_t ACameraManager_isCameraDeviceSharingSupported(
+ ACameraManager *manager,
+ const char *cameraId,
+ bool *isSharingSupported) __INTRODUCED_IN(36);
+
#ifdef __ANDROID_VNDK__
/**
* Retrieve the tag value, given the tag name and camera id.
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 704b46e..fc6b932 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -91,6 +91,7 @@
ACAMERA_AUTOMOTIVE_LENS,
ACAMERA_EXTENSION,
ACAMERA_JPEGR,
+ ACAMERA_SHARED_SESSION,
ACAMERA_SECTION_COUNT,
ACAMERA_VENDOR = 0x8000
@@ -138,6 +139,7 @@
ACAMERA_AUTOMOTIVE_LENS_START = ACAMERA_AUTOMOTIVE_LENS << 16,
ACAMERA_EXTENSION_START = ACAMERA_EXTENSION << 16,
ACAMERA_JPEGR_START = ACAMERA_JPEGR << 16,
+ ACAMERA_SHARED_SESSION_START = ACAMERA_SHARED_SESSION << 16,
ACAMERA_VENDOR_START = ACAMERA_VENDOR << 16
} acamera_metadata_section_start_t;
@@ -12079,6 +12081,7 @@
+
__END_DECLS
#endif /* _NDK_CAMERA_METADATA_TAGS_H */
diff --git a/camera/ndk/libcamera2ndk.map.txt b/camera/ndk/libcamera2ndk.map.txt
index 7d7868b..60d4775 100644
--- a/camera/ndk/libcamera2ndk.map.txt
+++ b/camera/ndk/libcamera2ndk.map.txt
@@ -28,6 +28,8 @@
ACameraManager_getCameraCharacteristics;
ACameraManager_getCameraIdList;
ACameraManager_openCamera;
+ ACameraManager_openSharedCamera; # systemapi introduced=36
+ ACameraManager_isCameraDeviceSharingSupported; # systemapi introduced=36
ACameraManager_registerAvailabilityCallback;
ACameraManager_unregisterAvailabilityCallback;
ACameraManager_registerExtendedAvailabilityCallback; # introduced=29
@@ -72,6 +74,9 @@
ACaptureSessionSharedOutput_remove; # introduced=28
ACaptureSessionPhysicalOutput_create; # introduced=29
ACaptureSessionOutput_free;
+ ACameraCaptureSessionShared_startStreaming; # systemapi introduced=36
+ ACameraCaptureSessionShared_logicalCamera_startStreaming; # systemapi introduced=36
+ ACameraCaptureSessionShared_stopStreaming; # systemapi introduced=36
local:
*;
};
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index 9ed8197..d3a8e0d 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -85,11 +85,12 @@
const char* id,
ACameraDevice_StateCallbacks* cb,
sp<ACameraMetadata> chars,
- ACameraDevice* wrapper) :
+ ACameraDevice* wrapper, bool sharedMode) :
mCameraId(id),
mAppCallbacks(*cb),
mChars(std::move(chars)),
mWrapper(wrapper),
+ mSharedMode(sharedMode),
mInError(false),
mError(ACAMERA_OK),
mIdle(true),
@@ -960,6 +961,7 @@
case kWhatCaptureSeqAbort:
case kWhatCaptureBufferLost:
case kWhatPreparedCb:
+ case kWhatClientSharedAccessPriorityChanged:
ALOGV("%s: Received msg %d", __FUNCTION__, msg->what());
break;
case kWhatCleanUpSessions:
@@ -997,6 +999,28 @@
(*onDisconnected)(context, dev);
break;
}
+ case kWhatClientSharedAccessPriorityChanged:
+ {
+ ACameraDevice* dev;
+ found = msg->findPointer(kDeviceKey, (void**) &dev);
+ if (!found || dev == nullptr) {
+ ALOGE("%s: Cannot find device pointer!", __FUNCTION__);
+ return;
+ }
+ ACameraDevice_ClientSharedAccessPriorityChangedCallback
+ onClientSharedAccessPriorityChanged;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onClientSharedAccessPriorityChanged);
+ if (!found) {
+ ALOGE("%s: Cannot find onClientSharedAccessPriorityChanged!", __FUNCTION__);
+ return;
+ }
+ if (onClientSharedAccessPriorityChanged == nullptr) {
+ return;
+ }
+ (*onClientSharedAccessPriorityChanged)(context, dev, dev->isPrimaryClient());
+ break;
+ }
+
case kWhatOnError:
{
ACameraDevice* dev;
@@ -1614,6 +1638,28 @@
return ScopedAStatus::ok();
}
+ScopedAStatus CameraDevice::ServiceCallback::onClientSharedAccessPriorityChanged(
+ bool primaryClient) {
+ ALOGV("onClientSharedAccessPriorityChanged received. primaryClient = %d", primaryClient);
+ ScopedAStatus ret = ScopedAStatus::ok();
+ std::shared_ptr<CameraDevice> dev = mDevice.lock();
+ if (dev == nullptr) {
+ return ret; // device has been closed
+ }
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->isClosed() || dev->mRemote == nullptr) {
+ return ret;
+ }
+ dev->setPrimaryClient(primaryClient);
+ sp<AMessage> msg = new AMessage(kWhatClientSharedAccessPriorityChanged, dev->mHandler);
+ msg->setPointer(kContextKey, dev->mAppCallbacks.context);
+ msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
+ msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onClientSharedAccessPriorityChanged);
+ msg->post();
+
+ return ScopedAStatus::ok();
+}
+
ScopedAStatus CameraDevice::ServiceCallback::onDeviceIdle() {
ALOGV("Camera is now idle");
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index b771d47..6ba30bb 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -95,7 +95,7 @@
public:
CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
sp<ACameraMetadata> chars,
- ACameraDevice* wrapper);
+ ACameraDevice* wrapper, bool sharedMode);
~CameraDevice();
// Called to initialize fields that require shared_ptr to `this`
@@ -136,6 +136,7 @@
const CaptureResultExtras& in_resultExtras,
const std::vector<PhysicalCaptureResultInfo>&
in_physicalCaptureResultInfos) override;
+ ndk::ScopedAStatus onClientSharedAccessPriorityChanged(bool isPrimaryClient) override;
private:
camera_status_t readOneResultMetadata(const CaptureMetadataInfo& captureMetadataInfo,
@@ -154,6 +155,8 @@
// Stop the looper thread and unregister the handler
void stopLooperAndDisconnect();
+ void setPrimaryClient(bool isPrimary) {mIsPrimaryClient = isPrimary;};
+ bool isPrimaryClient() {return mIsPrimaryClient;};
private:
friend ACameraCaptureSession;
@@ -232,6 +235,8 @@
const sp<ACameraMetadata> mChars; // Camera characteristics
std::shared_ptr<ServiceCallback> mServiceCallback;
ACameraDevice* mWrapper;
+ bool mSharedMode;
+ bool mIsPrimaryClient;
// stream id -> pair of (ACameraWindowType* from application, OutputConfiguration used for
// camera service)
@@ -274,7 +279,8 @@
kWhatCaptureBufferLost, // onCaptureBufferLost
kWhatPreparedCb, // onPrepared
// Internal cleanup
- kWhatCleanUpSessions // Cleanup cached sp<ACameraCaptureSession>
+ kWhatCleanUpSessions, // Cleanup cached sp<ACameraCaptureSession>
+ kWhatClientSharedAccessPriorityChanged
};
static const char* kContextKey;
static const char* kDeviceKey;
@@ -434,9 +440,9 @@
*/
struct ACameraDevice {
ACameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
- sp<ACameraMetadata> chars) :
+ sp<ACameraMetadata> chars, bool sharedMode) :
mDevice(std::make_shared<android::acam::CameraDevice>(id, cb,
- std::move(chars), this)) {
+ std::move(chars), this, sharedMode)) {
mDevice->init();
}
@@ -481,6 +487,13 @@
inline bool setDeviceMetadataQueues() {
return mDevice->setDeviceMetadataQueues();
}
+ inline void setPrimaryClient(bool isPrimary) {
+ mDevice->setPrimaryClient(isPrimary);
+ }
+ inline bool isPrimaryClient() {
+ return mDevice->isPrimaryClient();
+ }
+
private:
std::shared_ptr<android::acam::CameraDevice> mDevice;
};
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
index 5b69f5c..c34c4bd 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -789,10 +789,33 @@
}
camera_status_t
-ACameraManager::openCamera(
+ACameraManager::isCameraDeviceSharingSupported(
const char* cameraId,
+ /*out*/bool* isSharingSupported) {
+ sp<ACameraMetadata> spChars;
+ camera_status_t ret = getCameraCharacteristics(cameraId, &spChars);
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: cannot get camera characteristics for camera %s. err %d",
+ __FUNCTION__, cameraId, ret);
+ return ret;
+ }
+
+ ACameraMetadata* chars = spChars.get();
+ ACameraMetadata_const_entry entry;
+ ret = ACameraMetadata_getConstEntry(chars, ANDROID_SHARED_SESSION_OUTPUT_CONFIGURATIONS,
+ &entry);
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+ *isSharingSupported = (entry.count > 0) ? true : false;
+ return ACAMERA_OK;
+}
+
+camera_status_t
+ACameraManager::openCamera(
+ const char* cameraId, bool sharedMode,
ACameraDevice_StateCallbacks* callback,
- /*out*/ACameraDevice** outDevice) {
+ /*out*/ACameraDevice** outDevice, /*out*/bool* isPrimaryClient) {
sp<ACameraMetadata> rawChars;
camera_status_t ret = getCameraCharacteristics(cameraId, &rawChars);
Mutex::Autolock _l(mLock);
@@ -802,7 +825,7 @@
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(rawChars));
+ ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(rawChars), sharedMode);
std::shared_ptr<ICameraService> cs = CameraManagerGlobal::getInstance()->getCameraService();
if (cs == nullptr) {
@@ -813,11 +836,18 @@
std::shared_ptr<BnCameraDeviceCallback> deviceCallback = device->getServiceCallback();
std::shared_ptr<ICameraDeviceUser> deviceRemote;
+ ScopedAStatus serviceRet;
// No way to get package name from native.
// Send a zero length package name and let camera service figure it out from UID
- ScopedAStatus serviceRet = cs->connectDevice(deviceCallback,
- std::string(cameraId), &deviceRemote);
+ if (sharedMode) {
+ serviceRet = cs->connectDeviceV2(deviceCallback,
+ std::string(cameraId), sharedMode, &deviceRemote);
+ } else {
+ serviceRet = cs->connectDevice(deviceCallback,
+ std::string(cameraId), &deviceRemote);
+ }
+
if (!serviceRet.isOk()) {
if (serviceRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
Status errStatus = static_cast<Status>(serviceRet.getServiceSpecificError());
@@ -840,6 +870,13 @@
}
device->setRemoteDevice(deviceRemote);
+ if (sharedMode) {
+ ScopedAStatus remoteRet = deviceRemote->isPrimaryClient(isPrimaryClient);
+ if (!remoteRet.isOk()) {
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ device->setPrimaryClient(*isPrimaryClient);
+ }
device->setDeviceMetadataQueues();
*outDevice = device;
return ACAMERA_OK;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
index 5688e76..e9973e6 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -261,9 +261,9 @@
camera_status_t getCameraCharacteristics(
const char* cameraId, android::sp<ACameraMetadata>* characteristics);
- camera_status_t openCamera(const char* cameraId,
- ACameraDevice_StateCallbacks* callback,
- /*out*/ACameraDevice** device);
+ camera_status_t openCamera(const char* cameraId, bool sharedMode,
+ ACameraDevice_StateCallbacks* callback, /*out*/ACameraDevice** device,
+ /*out*/bool* primaryClient);
camera_status_t getTagFromName(const char *cameraId, const char *name, uint32_t *tag);
void registerAvailabilityCallback(const ACameraManager_AvailabilityCallbacks* callback);
void unregisterAvailabilityCallback(const ACameraManager_AvailabilityCallbacks* callback);
@@ -271,6 +271,8 @@
const ACameraManager_ExtendedAvailabilityCallbacks* callback);
void unregisterExtendedAvailabilityCallback(
const ACameraManager_ExtendedAvailabilityCallbacks* callback);
+ camera_status_t isCameraDeviceSharingSupported(const char *cameraId,
+ bool *isSharingSupported);
private:
enum {
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 5135b5d..4384df9 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -130,6 +130,15 @@
return binder::Status::ok();
}
+ virtual binder::Status onCameraOpenedInSharedMode(
+ [[maybe_unused]] const std::string& /*cameraId*/,
+ [[maybe_unused]] const std::string& /*clientPackageName*/,
+ [[maybe_unused]] int32_t /*deviceId*/,
+ [[maybe_unused]] bool /*isPrimaryClient*/) override {
+ // No op
+ return binder::Status::ok();
+ }
+
bool waitForNumCameras(size_t num) const {
Mutex::Autolock l(mLock);
@@ -281,6 +290,12 @@
return binder::Status::ok();
}
+ virtual binder::Status onClientSharedAccessPriorityChanged(
+ [[maybe_unused]] bool /*isPrimaryClient*/) {
+ // No-op
+ return binder::Status::ok();
+ }
+
// Test helper functions:
bool hadError() const {
@@ -402,7 +417,8 @@
res = service->connectDevice(callbacks, cameraId,
/*oomScoreOffset*/ 0,
/*targetSdkVersion*/__ANDROID_API_FUTURE__,
- /*overrideToPortrait*/false, clientAttribution, /*devicePolicy*/0, /*out*/&device);
+ /*overrideToPortrait*/false, clientAttribution, /*devicePolicy*/0,
+ /*sharedMode*/false, /*out*/&device);
EXPECT_TRUE(res.isOk()) << res;
ASSERT_NE(nullptr, device.get());
device->disconnect();
@@ -451,7 +467,7 @@
/*oomScoreOffset*/ 0,
/*targetSdkVersion*/__ANDROID_API_FUTURE__,
/*overrideToPortrait*/false, clientAttribution, /*devicePolicy*/0,
- /*out*/&device);
+ /*sharedMode*/false, /*out*/&device);
EXPECT_TRUE(res.isOk()) << res;
}
auto p = std::make_pair(callbacks, device);