blob: 5a824cc9974e685ceb1d433e020a19a71aed40c7 [file] [log] [blame]
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +01001/*
Biswarup Pal6152a302023-12-19 12:44:09 +00002 * Copyright 2023 The Android Open Source Project
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +01003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// #define LOG_NDEBUG 0
18#define LOG_TAG "VirtualCameraDevice"
19#include "VirtualCameraDevice.h"
20
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010021#include <algorithm>
22#include <array>
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010023#include <chrono>
24#include <cstdint>
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010025#include <iterator>
26#include <optional>
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010027#include <string>
28
29#include "VirtualCameraSession.h"
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010030#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
Biswarup Pal6152a302023-12-19 12:44:09 +000031#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010032#include "aidl/android/hardware/camera/common/Status.h"
33#include "aidl/android/hardware/camera/device/CameraMetadata.h"
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010034#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010035#include "android/binder_auto_utils.h"
36#include "android/binder_status.h"
37#include "log/log.h"
38#include "system/camera_metadata.h"
39#include "util/MetadataBuilder.h"
40#include "util/Util.h"
41
42namespace android {
43namespace companion {
44namespace virtualcamera {
45
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010046using ::aidl::android::companion::virtualcamera::Format;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010047using ::aidl::android::companion::virtualcamera::IVirtualCameraCallback;
Biswarup Pal112458f2023-12-28 19:50:17 +000048using ::aidl::android::companion::virtualcamera::LensFacing;
Biswarup Pal6152a302023-12-19 12:44:09 +000049using ::aidl::android::companion::virtualcamera::SensorOrientation;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010050using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
Biswarup Pal6152a302023-12-19 12:44:09 +000051using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010052using ::aidl::android::hardware::camera::common::CameraResourceCost;
53using ::aidl::android::hardware::camera::common::Status;
54using ::aidl::android::hardware::camera::device::CameraMetadata;
55using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
56using ::aidl::android::hardware::camera::device::ICameraDeviceSession;
57using ::aidl::android::hardware::camera::device::ICameraInjectionSession;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010058using ::aidl::android::hardware::camera::device::Stream;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010059using ::aidl::android::hardware::camera::device::StreamConfiguration;
60using ::aidl::android::hardware::camera::device::StreamRotation;
61using ::aidl::android::hardware::camera::device::StreamType;
62using ::aidl::android::hardware::graphics::common::PixelFormat;
63
64namespace {
65
66using namespace std::chrono_literals;
67
68// Prefix of camera name - "device@1.1/virtual/{numerical_id}"
69const char* kDevicePathPrefix = "device@1.1/virtual/";
70
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010071constexpr int32_t kMaxJpegSize = 3 * 1024 * 1024 /*3MiB*/;
72
73constexpr MetadataBuilder::ControlRegion kDefaultEmptyControlRegion{};
74
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +010075const std::array<PixelFormat, 3> kOutputFormats{
76 PixelFormat::IMPLEMENTATION_DEFINED, PixelFormat::YCBCR_420_888,
77 PixelFormat::BLOB};
Biswarup Pal6152a302023-12-19 12:44:09 +000078
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +010079bool isSupportedOutputFormat(const PixelFormat pixelFormat) {
80 return std::find(kOutputFormats.begin(), kOutputFormats.end(), pixelFormat) !=
81 kOutputFormats.end();
82}
83
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010084std::optional<Resolution> getMaxResolution(
85 const std::vector<SupportedStreamConfiguration>& configs) {
86 auto itMax = std::max_element(configs.begin(), configs.end(),
87 [](const SupportedStreamConfiguration& a,
88 const SupportedStreamConfiguration& b) {
89 return a.width * b.height < a.width * b.height;
90 });
91 if (itMax == configs.end()) {
92 ALOGE(
93 "%s: empty vector of supported configurations, cannot find largest "
94 "resolution.",
95 __func__);
96 return std::nullopt;
97 }
98
99 return Resolution(itMax->width, itMax->height);
100}
101
Biswarup Pal6152a302023-12-19 12:44:09 +0000102// Returns a map of unique resolution to maximum maxFps for all streams with
103// that resolution.
104std::map<Resolution, int> getResolutionToMaxFpsMap(
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100105 const std::vector<SupportedStreamConfiguration>& configs) {
Biswarup Pal6152a302023-12-19 12:44:09 +0000106 std::map<Resolution, int> resolutionToMaxFpsMap;
107
108 for (const SupportedStreamConfiguration& config : configs) {
109 Resolution resolution(config.width, config.height);
110 if (resolutionToMaxFpsMap.find(resolution) == resolutionToMaxFpsMap.end()) {
111 resolutionToMaxFpsMap[resolution] = config.maxFps;
112 } else {
113 int currentMaxFps = resolutionToMaxFpsMap[resolution];
114 resolutionToMaxFpsMap[resolution] = std::max(currentMaxFps, config.maxFps);
115 }
116 }
117
118 return resolutionToMaxFpsMap;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100119}
120
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100121// TODO(b/301023410) - Populate camera characteristics according to camera configuration.
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100122std::optional<CameraMetadata> initCameraCharacteristics(
Biswarup Pal6152a302023-12-19 12:44:09 +0000123 const std::vector<SupportedStreamConfiguration>& supportedInputConfig,
Biswarup Pal112458f2023-12-28 19:50:17 +0000124 const SensorOrientation sensorOrientation, const LensFacing lensFacing) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100125 if (!std::all_of(supportedInputConfig.begin(), supportedInputConfig.end(),
126 [](const SupportedStreamConfiguration& config) {
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100127 return isFormatSupportedForInput(
Biswarup Pal6152a302023-12-19 12:44:09 +0000128 config.width, config.height, config.pixelFormat,
129 config.maxFps);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100130 })) {
Jan Sebechlebsky042d1fb2023-12-12 16:37:00 +0100131 ALOGE("%s: input configuration contains unsupported format", __func__);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100132 return std::nullopt;
133 }
134
135 MetadataBuilder builder =
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100136 MetadataBuilder()
137 .setSupportedHardwareLevel(
138 ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL)
139 .setFlashAvailable(false)
Biswarup Pal112458f2023-12-28 19:50:17 +0000140 .setLensFacing(
141 static_cast<camera_metadata_enum_android_lens_facing>(lensFacing))
Biswarup Pald9be04d2024-01-31 14:35:15 +0000142 .setFocalLength(43.0)
Biswarup Pal6152a302023-12-19 12:44:09 +0000143 .setSensorOrientation(static_cast<int32_t>(sensorOrientation))
Jan Sebechlebskya984ffb2024-02-01 09:12:37 +0100144 .setSensorReadoutTimestamp(
145 ANDROID_SENSOR_READOUT_TIMESTAMP_NOT_SUPPORTED)
Jan Sebechlebskyad8d35f2024-02-05 11:58:59 +0100146 .setSensorTimestampSource(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN)
Biswarup Pald9be04d2024-01-31 14:35:15 +0000147 .setSensorPhysicalSize(36.0, 24.0)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100148 .setAvailableFaceDetectModes({ANDROID_STATISTICS_FACE_DETECT_MODE_OFF})
Jan Sebechlebskyb0119fa2023-12-04 10:29:06 +0100149 .setAvailableMaxDigitalZoom(1.0)
150 .setControlAvailableModes({ANDROID_CONTROL_MODE_AUTO})
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100151 .setControlAfAvailableModes({ANDROID_CONTROL_AF_MODE_OFF})
Jan Sebechlebsky4425a732024-01-31 11:31:54 +0100152 .setControlAvailableSceneModes({ANDROID_CONTROL_SCENE_MODE_DISABLED})
153 .setControlAvailableEffects({ANDROID_CONTROL_EFFECT_MODE_OFF})
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100154 .setControlAeAvailableFpsRange(10, 30)
155 .setControlMaxRegions(0, 0, 0)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100156 .setControlAfRegions({kDefaultEmptyControlRegion})
157 .setControlAeRegions({kDefaultEmptyControlRegion})
158 .setControlAwbRegions({kDefaultEmptyControlRegion})
159 .setControlAeCompensationRange(0, 1)
160 .setControlAeCompensationStep(camera_metadata_rational_t{0, 1})
Jan Sebechlebsky4425a732024-01-31 11:31:54 +0100161 .setControlAwbLockAvailable(false)
162 .setControlAeLockAvailable(false)
163 .setControlAvailableAwbModes({ANDROID_CONTROL_AWB_MODE_AUTO})
Jan Sebechlebsky6ab07fe2023-12-05 15:23:34 +0100164 .setControlZoomRatioRange(/*min=*/1.0, /*max=*/1.0)
Jan Sebechlebskyad8d35f2024-02-05 11:58:59 +0100165 // TODO(b/301023410) Add JPEG Exif + thumbnail support.
166 .setJpegAvailableThumbnailSizes({Resolution(0, 0)})
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100167 .setMaxJpegSize(kMaxJpegSize)
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100168 .setMaxNumberOutputStreams(
169 VirtualCameraDevice::kMaxNumberOfRawStreams,
170 VirtualCameraDevice::kMaxNumberOfProcessedStreams,
171 VirtualCameraDevice::kMaxNumberOfStallStreams)
Jan Sebechlebsky4425a732024-01-31 11:31:54 +0100172 .setSyncMaxLatency(ANDROID_SYNC_MAX_LATENCY_UNKNOWN)
173 .setAvailableRequestKeys({})
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100174 .setAvailableRequestKeys({ANDROID_CONTROL_AF_MODE})
175 .setAvailableResultKeys({ANDROID_CONTROL_AF_MODE})
176 .setAvailableCapabilities(
Jan Sebechlebskyad8d35f2024-02-05 11:58:59 +0100177 {ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE});
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100178
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100179 // Active array size must correspond to largest supported input resolution.
180 std::optional<Resolution> maxResolution =
181 getMaxResolution(supportedInputConfig);
182 if (!maxResolution.has_value()) {
183 return std::nullopt;
184 }
185 builder.setSensorActiveArraySize(0, 0, maxResolution->width,
186 maxResolution->height);
Biswarup Pald9be04d2024-01-31 14:35:15 +0000187 builder.setSensorPixelArraySize(maxResolution->width, maxResolution->height);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100188
189 std::vector<MetadataBuilder::StreamConfiguration> outputConfigurations;
190
191 // TODO(b/301023410) Add also all "standard" resolutions we can rescale the
192 // streams to (all standard resolutions with same aspect ratio).
193
Biswarup Pal6152a302023-12-19 12:44:09 +0000194 std::map<Resolution, int> resolutionToMaxFpsMap =
195 getResolutionToMaxFpsMap(supportedInputConfig);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100196
Biswarup Pal6152a302023-12-19 12:44:09 +0000197 // Add configurations for all unique input resolutions and output formats.
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100198 for (const PixelFormat format : kOutputFormats) {
Biswarup Pal6152a302023-12-19 12:44:09 +0000199 std::transform(
200 resolutionToMaxFpsMap.begin(), resolutionToMaxFpsMap.end(),
201 std::back_inserter(outputConfigurations), [format](const auto& entry) {
202 Resolution resolution = entry.first;
203 int maxFps = entry.second;
204 return MetadataBuilder::StreamConfiguration{
205 .width = resolution.width,
206 .height = resolution.height,
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100207 .format = static_cast<int32_t>(format),
Biswarup Pal6152a302023-12-19 12:44:09 +0000208 .minFrameDuration = std::chrono::nanoseconds(1s) / maxFps,
209 .minStallDuration = 0s};
210 });
211 }
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100212
213 ALOGV("Adding %zu output configurations", outputConfigurations.size());
214 builder.setAvailableOutputStreamConfigurations(outputConfigurations);
215
Jan Sebechlebskyad8d35f2024-02-05 11:58:59 +0100216 auto metadata = builder.setAvailableCharacteristicKeys().build();
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100217 if (metadata == nullptr) {
218 ALOGE("Failed to build metadata!");
219 return CameraMetadata();
220 }
221
222 return std::move(*metadata);
223}
224
225} // namespace
226
227VirtualCameraDevice::VirtualCameraDevice(
Biswarup Pal6152a302023-12-19 12:44:09 +0000228 const uint32_t cameraId, const VirtualCameraConfiguration& configuration)
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100229 : mCameraId(cameraId),
Biswarup Pal6152a302023-12-19 12:44:09 +0000230 mVirtualCameraClientCallback(configuration.virtualCameraCallback),
231 mSupportedInputConfigurations(configuration.supportedStreamConfigs) {
232 std::optional<CameraMetadata> metadata = initCameraCharacteristics(
Biswarup Pal112458f2023-12-28 19:50:17 +0000233 mSupportedInputConfigurations, configuration.sensorOrientation,
234 configuration.lensFacing);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100235 if (metadata.has_value()) {
236 mCameraCharacteristics = *metadata;
237 } else {
238 ALOGE(
239 "%s: Failed to initialize camera characteristic based on provided "
240 "configuration.",
241 __func__);
242 }
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100243}
244
245ndk::ScopedAStatus VirtualCameraDevice::getCameraCharacteristics(
246 CameraMetadata* _aidl_return) {
247 ALOGV("%s", __func__);
248 if (_aidl_return == nullptr) {
249 return cameraStatus(Status::ILLEGAL_ARGUMENT);
250 }
251
252 *_aidl_return = mCameraCharacteristics;
253 return ndk::ScopedAStatus::ok();
254}
255
256ndk::ScopedAStatus VirtualCameraDevice::getPhysicalCameraCharacteristics(
257 const std::string& in_physicalCameraId, CameraMetadata* _aidl_return) {
258 ALOGV("%s: physicalCameraId %s", __func__, in_physicalCameraId.c_str());
259 (void)_aidl_return;
260
261 // VTS tests expect this call to fail with illegal argument status for
262 // all publicly advertised camera ids.
263 // Because we don't support physical camera ids, we just always
264 // fail with illegal argument (there's no valid argument to provide).
265 return cameraStatus(Status::ILLEGAL_ARGUMENT);
266}
267
268ndk::ScopedAStatus VirtualCameraDevice::getResourceCost(
269 CameraResourceCost* _aidl_return) {
270 ALOGV("%s", __func__);
271 if (_aidl_return == nullptr) {
272 return cameraStatus(Status::ILLEGAL_ARGUMENT);
273 }
274 _aidl_return->resourceCost = 100; // ¯\_(ツ)_/¯
275 return ndk::ScopedAStatus::ok();
276}
277
278ndk::ScopedAStatus VirtualCameraDevice::isStreamCombinationSupported(
279 const StreamConfiguration& in_streams, bool* _aidl_return) {
280 ALOGV("%s", __func__);
281
282 if (_aidl_return == nullptr) {
283 return cameraStatus(Status::ILLEGAL_ARGUMENT);
284 }
285
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100286 *_aidl_return = isStreamCombinationSupported(in_streams);
287 return ndk::ScopedAStatus::ok();
288};
289
290bool VirtualCameraDevice::isStreamCombinationSupported(
291 const StreamConfiguration& streamConfiguration) const {
Jan Sebechlebsky39129f82024-01-19 16:42:11 +0100292 if (streamConfiguration.streams.empty()) {
293 ALOGE("%s: Querying empty configuration", __func__);
294 return false;
295 }
296
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100297 int numberOfProcessedStreams = 0;
298 int numberOfStallStreams = 0;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100299 for (const Stream& stream : streamConfiguration.streams) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100300 ALOGV("%s: Configuration queried: %s", __func__, stream.toString().c_str());
301
302 if (stream.streamType == StreamType::INPUT) {
303 ALOGW("%s: Input stream type is not supported", __func__);
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100304 return false;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100305 }
306
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100307 if (stream.rotation != StreamRotation::ROTATION_0 ||
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100308 !isSupportedOutputFormat(stream.format)) {
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100309 ALOGV("Unsupported output stream type");
310 return false;
311 }
312
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100313 if (stream.format == PixelFormat::BLOB) {
314 numberOfStallStreams++;
315 } else {
316 numberOfProcessedStreams++;
317 }
318
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100319 auto matchesSupportedInputConfig =
320 [&stream](const SupportedStreamConfiguration& config) {
321 return stream.width == config.width && stream.height == config.height;
322 };
323 if (std::none_of(mSupportedInputConfigurations.begin(),
324 mSupportedInputConfigurations.end(),
325 matchesSupportedInputConfig)) {
326 ALOGV("Requested config doesn't match any supported input config");
327 return false;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100328 }
329 }
Jan Sebechlebsky8ae23592024-02-02 16:08:18 +0100330
331 if (numberOfProcessedStreams > kMaxNumberOfProcessedStreams) {
332 ALOGE("%s: %d processed streams exceeds the supported maximum of %d",
333 __func__, numberOfProcessedStreams, kMaxNumberOfProcessedStreams);
334 return false;
335 }
336
337 if (numberOfStallStreams > kMaxNumberOfStallStreams) {
338 ALOGE("%s: %d stall streams exceeds the supported maximum of %d", __func__,
339 numberOfStallStreams, kMaxNumberOfStallStreams);
340 return false;
341 }
342
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100343 return true;
344}
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100345
346ndk::ScopedAStatus VirtualCameraDevice::open(
347 const std::shared_ptr<ICameraDeviceCallback>& in_callback,
348 std::shared_ptr<ICameraDeviceSession>* _aidl_return) {
349 ALOGV("%s", __func__);
350
351 *_aidl_return = ndk::SharedRefBase::make<VirtualCameraSession>(
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100352 sharedFromThis(), in_callback, mVirtualCameraClientCallback);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100353
354 return ndk::ScopedAStatus::ok();
355};
356
357ndk::ScopedAStatus VirtualCameraDevice::openInjectionSession(
358 const std::shared_ptr<ICameraDeviceCallback>& in_callback,
359 std::shared_ptr<ICameraInjectionSession>* _aidl_return) {
360 ALOGV("%s", __func__);
361
362 (void)in_callback;
363 (void)_aidl_return;
364 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
365}
366
367ndk::ScopedAStatus VirtualCameraDevice::setTorchMode(bool in_on) {
368 ALOGV("%s: on = %s", __func__, in_on ? "on" : "off");
369 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
370}
371
372ndk::ScopedAStatus VirtualCameraDevice::turnOnTorchWithStrengthLevel(
373 int32_t in_torchStrength) {
374 ALOGV("%s: torchStrength = %d", __func__, in_torchStrength);
375 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
376}
377
378ndk::ScopedAStatus VirtualCameraDevice::getTorchStrengthLevel(
379 int32_t* _aidl_return) {
380 (void)_aidl_return;
381 return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
382}
383
384binder_status_t VirtualCameraDevice::dump(int fd, const char** args,
385 uint32_t numArgs) {
386 // TODO(b/301023410) Implement.
387 (void)fd;
388 (void)args;
389 (void)numArgs;
390 return STATUS_OK;
391}
392
393std::string VirtualCameraDevice::getCameraName() const {
394 return std::string(kDevicePathPrefix) + std::to_string(mCameraId);
395}
396
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100397std::shared_ptr<VirtualCameraDevice> VirtualCameraDevice::sharedFromThis() {
398 // SharedRefBase which BnCameraDevice inherits from breaks
399 // std::enable_shared_from_this. This is recommended replacement for
400 // shared_from_this() per documentation in binder_interface_utils.h.
401 return ref<VirtualCameraDevice>();
402}
403
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100404} // namespace virtualcamera
405} // namespace companion
406} // namespace android