Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5cb3996f authored by Jan Sebechlebsky's avatar Jan Sebechlebsky
Browse files

Move virtual camera service to frameworks/av/services

Bug: 311647154
Bug: 301023410
Test: atest virtual_camera_tests
Test: build & flash & adb shell cmd virtual_camera help
Change-Id: I6d43a2b70f454c9c01ec2abcae9f138cd78c6a85
parent baaf11c8
Loading
Loading
Loading
Loading
+99 −0
Original line number Diff line number Diff line
package {
    // See: http://go/android-license-faq
    default_applicable_licenses: ["Android-Apache-2.0"],
}

cc_defaults {
    name: "libvirtualcamera_defaults",
    shared_libs: [
        "android.hardware.common-V2-ndk",
        "android.hardware.common.fmq-V1-ndk",
        "libbinder",
        "libbinder_ndk",
        "libcamera_metadata",
        "liblog",
        "libfmq",
        "libgui",
        "libjpeg",
        "libnativewindow",
        "libbase",
        "libcutils",
        "libui",
        "libutils",
        "libEGL",
        "libGLESv2",
        "libGLESv3",
    ],
    static_libs: [
        "android.hardware.camera.common@1.0-helper",
        "android.hardware.camera.common-V1-ndk",
        "android.hardware.camera.device-V2-ndk",
        "android.hardware.camera.metadata-V2-ndk",
        "android.hardware.camera.provider-V2-ndk",
        "libaidlcommonsupport",
        "virtual_camera_service_aidl-ndk",
    ],
    cflags: [
        "-Wall",
        "-Werror",
        "-Wformat",
        "-Wthread-safety",
        "-DLOG_NDEBUG=0"
    ],
}

cc_library_static {
    name: "libvirtualcamera_utils",
    srcs: [
        "util/JpegUtil.cc",
        "util/MetadataBuilder.cc",
        "util/Util.cc",
        "util/TestPatternHelper.cc",
        "util/EglDisplayContext.cc",
        "util/EglFramebuffer.cc",
        "util/EglProgram.cc",
        "util/EglSurfaceTexture.cc",
        "util/EglUtil.cc",
    ],
    defaults: [
        "libvirtualcamera_defaults",
    ],
}

cc_library_static {
    name: "libvirtualcamera",
    srcs: [
        "VirtualCameraProvider.cc",
        "VirtualCameraDevice.cc",
        "VirtualCameraSession.cc",
        "VirtualCameraStream.cc",
        "VirtualCameraService.cc",
        "VirtualCameraSessionContext.cc",
        "VirtualCameraRenderThread.cc",
    ],
    defaults: [
        "libvirtualcamera_defaults",
    ],
    static_libs: [
        "libvirtualcamera_utils",
    ],
    export_include_dirs: ["."],
    min_sdk_version: "current",
}

cc_binary {
    name: "virtual_camera",
    srcs: ["main.cc"],
    defaults: [
        "libvirtualcamera_defaults",
    ],
    static_libs: [
        "libvirtualcamera",
        "libvirtualcamera_utils",
    ],
    // Remove before flight.
    // We don't want the service to be started and discovered
    // yet - remove comments on the lines below in order to
    // test locally.
    // init_rc: ["virtual_camera.hal.rc"],
}
+7 −0
Original line number Diff line number Diff line
{
  "postsubmit": [
    {
      "name": "virtual_camera_tests"
    }
  ]
}
+248 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// #define LOG_NDEBUG 0
#define LOG_TAG "VirtualCameraDevice"
#include "VirtualCameraDevice.h"

#include <chrono>
#include <cstdint>
#include <string>

#include "VirtualCameraSession.h"
#include "aidl/android/hardware/camera/common/Status.h"
#include "aidl/android/hardware/camera/device/CameraMetadata.h"
#include "android/binder_auto_utils.h"
#include "android/binder_status.h"
#include "log/log.h"
#include "system/camera_metadata.h"
#include "util/MetadataBuilder.h"
#include "util/Util.h"

namespace android {
namespace companion {
namespace virtualcamera {

using ::aidl::android::companion::virtualcamera::IVirtualCameraCallback;
using ::aidl::android::hardware::camera::common::CameraResourceCost;
using ::aidl::android::hardware::camera::common::Status;
using ::aidl::android::hardware::camera::device::CameraMetadata;
using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
using ::aidl::android::hardware::camera::device::ICameraDeviceSession;
using ::aidl::android::hardware::camera::device::ICameraInjectionSession;
using ::aidl::android::hardware::camera::device::StreamConfiguration;
using ::aidl::android::hardware::camera::device::StreamRotation;
using ::aidl::android::hardware::camera::device::StreamType;
using ::aidl::android::hardware::graphics::common::PixelFormat;

namespace {

using namespace std::chrono_literals;

// Prefix of camera name - "device@1.1/virtual/{numerical_id}"
const char* kDevicePathPrefix = "device@1.1/virtual/";

constexpr int32_t kVgaWidth = 640;
constexpr int32_t kVgaHeight = 480;
constexpr std::chrono::nanoseconds kMinFrameDuration30Fps = 1s / 30;
constexpr int32_t kMaxJpegSize = 3 * 1024 * 1024 /*3MiB*/;

constexpr MetadataBuilder::ControlRegion kDefaultEmptyControlRegion{};

// TODO(b/301023410) - Populate camera characteristics according to camera configuration.
CameraMetadata initCameraCharacteristics() {
  auto metadata =
      MetadataBuilder()
          .setSupportedHardwareLevel(
              ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL)
          .setFlashAvailable(false)
          .setLensFacing(ANDROID_LENS_FACING_EXTERNAL)
          .setSensorOrientation(0)
          .setAvailableFaceDetectModes({ANDROID_STATISTICS_FACE_DETECT_MODE_OFF})
          .setControlAfAvailableModes({ANDROID_CONTROL_AF_MODE_OFF})
          .setAvailableOutputStreamConfigurations(
              {MetadataBuilder::StreamConfiguration{
                   .width = kVgaWidth,
                   .height = kVgaHeight,
                   .format =
                       ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
                   .minFrameDuration = kMinFrameDuration30Fps,
                   .minStallDuration = 0s},
               MetadataBuilder::StreamConfiguration{
                   .width = kVgaWidth,
                   .height = kVgaHeight,
                   .format = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,
                   .minFrameDuration = kMinFrameDuration30Fps,
                   .minStallDuration = 0s},
               {MetadataBuilder::StreamConfiguration{
                   .width = kVgaWidth,
                   .height = kVgaHeight,
                   .format = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB,
                   .minFrameDuration = kMinFrameDuration30Fps,
                   .minStallDuration = 0s}}})
          .setControlAeAvailableFpsRange(10, 30)
          .setControlMaxRegions(0, 0, 0)
          .setSensorActiveArraySize(0, 0, kVgaWidth, kVgaHeight)
          .setControlAfRegions({kDefaultEmptyControlRegion})
          .setControlAeRegions({kDefaultEmptyControlRegion})
          .setControlAwbRegions({kDefaultEmptyControlRegion})
          .setControlAeCompensationRange(0, 1)
          .setControlAeCompensationStep(camera_metadata_rational_t{0, 1})
          .setMaxJpegSize(kMaxJpegSize)
          .setAvailableRequestKeys({ANDROID_CONTROL_AF_MODE})
          .setAvailableResultKeys({ANDROID_CONTROL_AF_MODE})
          .setAvailableCapabilities(
              {ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE})
          .setAvailableCharacteristicKeys()
          .build();

  if (metadata == nullptr) {
    ALOGE("Failed to build metadata!");
    return CameraMetadata();
  }

  return std::move(*metadata);
}

}  // namespace

VirtualCameraDevice::VirtualCameraDevice(
    const uint32_t cameraId,
    std::shared_ptr<IVirtualCameraCallback> virtualCameraClientCallback)
    : mCameraId(cameraId),
      mVirtualCameraClientCallback(virtualCameraClientCallback) {
  mCameraCharacteristics = initCameraCharacteristics();
}

ndk::ScopedAStatus VirtualCameraDevice::getCameraCharacteristics(
    CameraMetadata* _aidl_return) {
  ALOGV("%s", __func__);
  if (_aidl_return == nullptr) {
    return cameraStatus(Status::ILLEGAL_ARGUMENT);
  }

  *_aidl_return = mCameraCharacteristics;
  return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus VirtualCameraDevice::getPhysicalCameraCharacteristics(
    const std::string& in_physicalCameraId, CameraMetadata* _aidl_return) {
  ALOGV("%s: physicalCameraId %s", __func__, in_physicalCameraId.c_str());
  (void)_aidl_return;

  // VTS tests expect this call to fail with illegal argument status for
  // all publicly advertised camera ids.
  // Because we don't support physical camera ids, we just always
  // fail with illegal argument (there's no valid argument to provide).
  return cameraStatus(Status::ILLEGAL_ARGUMENT);
}

ndk::ScopedAStatus VirtualCameraDevice::getResourceCost(
    CameraResourceCost* _aidl_return) {
  ALOGV("%s", __func__);
  if (_aidl_return == nullptr) {
    return cameraStatus(Status::ILLEGAL_ARGUMENT);
  }
  _aidl_return->resourceCost = 100;  // ¯\_(ツ)_/¯
  return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus VirtualCameraDevice::isStreamCombinationSupported(
    const StreamConfiguration& in_streams, bool* _aidl_return) {
  ALOGV("%s", __func__);

  if (_aidl_return == nullptr) {
    return cameraStatus(Status::ILLEGAL_ARGUMENT);
  }

  for (const auto& stream : in_streams.streams) {
    ALOGV("%s: Configuration queried: %s", __func__, stream.toString().c_str());

    if (stream.streamType == StreamType::INPUT) {
      ALOGW("%s: Input stream type is not supported", __func__);
      *_aidl_return = false;
      return ndk::ScopedAStatus::ok();
    }

    // TODO(b/301023410) remove hardcoded format checks, verify against configuration.
    if (stream.width != 640 || stream.height != 480 ||
        stream.rotation != StreamRotation::ROTATION_0 ||
        (stream.format != PixelFormat::IMPLEMENTATION_DEFINED &&
         stream.format != PixelFormat::YCBCR_420_888 &&
         stream.format != PixelFormat::BLOB)) {
      *_aidl_return = false;
      return ndk::ScopedAStatus::ok();
    }
  }

  *_aidl_return = true;
  return ndk::ScopedAStatus::ok();
};

ndk::ScopedAStatus VirtualCameraDevice::open(
    const std::shared_ptr<ICameraDeviceCallback>& in_callback,
    std::shared_ptr<ICameraDeviceSession>* _aidl_return) {
  ALOGV("%s", __func__);

  *_aidl_return = ndk::SharedRefBase::make<VirtualCameraSession>(
      std::to_string(mCameraId), in_callback, mVirtualCameraClientCallback);

  return ndk::ScopedAStatus::ok();
};

ndk::ScopedAStatus VirtualCameraDevice::openInjectionSession(
    const std::shared_ptr<ICameraDeviceCallback>& in_callback,
    std::shared_ptr<ICameraInjectionSession>* _aidl_return) {
  ALOGV("%s", __func__);

  (void)in_callback;
  (void)_aidl_return;
  return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
}

ndk::ScopedAStatus VirtualCameraDevice::setTorchMode(bool in_on) {
  ALOGV("%s: on = %s", __func__, in_on ? "on" : "off");
  return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
}

ndk::ScopedAStatus VirtualCameraDevice::turnOnTorchWithStrengthLevel(
    int32_t in_torchStrength) {
  ALOGV("%s: torchStrength = %d", __func__, in_torchStrength);
  return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
}

ndk::ScopedAStatus VirtualCameraDevice::getTorchStrengthLevel(
    int32_t* _aidl_return) {
  (void)_aidl_return;
  return cameraStatus(Status::OPERATION_NOT_SUPPORTED);
}

binder_status_t VirtualCameraDevice::dump(int fd, const char** args,
                                          uint32_t numArgs) {
  // TODO(b/301023410) Implement.
  (void)fd;
  (void)args;
  (void)numArgs;
  return STATUS_OK;
}

std::string VirtualCameraDevice::getCameraName() const {
  return std::string(kDevicePathPrefix) + std::to_string(mCameraId);
}

}  // namespace virtualcamera
}  // namespace companion
}  // namespace android
+103 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERADEVICE_H
#define ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERADEVICE_H

#include <cstdint>
#include <memory>

#include "aidl/android/companion/virtualcamera/IVirtualCameraCallback.h"
#include "aidl/android/hardware/camera/device/BnCameraDevice.h"

namespace android {
namespace companion {
namespace virtualcamera {

// Representation of single virtual camera device, implements
// ICameraDevice AIDL to expose camera to camera framework.
class VirtualCameraDevice
    : public ::aidl::android::hardware::camera::device::BnCameraDevice {
 public:
  explicit VirtualCameraDevice(
      uint32_t cameraId,
      std::shared_ptr<
          ::aidl::android::companion::virtualcamera::IVirtualCameraCallback>
          virtualCameraClientCallback = nullptr);

  virtual ~VirtualCameraDevice() override = default;

  ndk::ScopedAStatus getCameraCharacteristics(
      ::aidl::android::hardware::camera::device::CameraMetadata* _aidl_return)
      override;

  ndk::ScopedAStatus getPhysicalCameraCharacteristics(
      const std::string& in_physicalCameraId,
      ::aidl::android::hardware::camera::device::CameraMetadata* _aidl_return)
      override;

  ndk::ScopedAStatus getResourceCost(
      ::aidl::android::hardware::camera::common::CameraResourceCost*
          _aidl_return) override;

  ndk::ScopedAStatus isStreamCombinationSupported(
      const ::aidl::android::hardware::camera::device::StreamConfiguration&
          in_streams,
      bool* _aidl_return) override;

  ndk::ScopedAStatus open(
      const std::shared_ptr<
          ::aidl::android::hardware::camera::device::ICameraDeviceCallback>&
          in_callback,
      std::shared_ptr<
          ::aidl::android::hardware::camera::device::ICameraDeviceSession>*
          _aidl_return) override;

  ndk::ScopedAStatus openInjectionSession(
      const std::shared_ptr<
          ::aidl::android::hardware::camera::device::ICameraDeviceCallback>&
          in_callback,
      std::shared_ptr<
          ::aidl::android::hardware::camera::device::ICameraInjectionSession>*
          _aidl_return) override;

  ndk::ScopedAStatus setTorchMode(bool in_on) override;

  ndk::ScopedAStatus turnOnTorchWithStrengthLevel(
      int32_t in_torchStrength) override;

  ndk::ScopedAStatus getTorchStrengthLevel(int32_t* _aidl_return) override;

  binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;

  // Returns unique virtual camera name in form
  // "device@{major}.{minor}/virtual/{numerical_id}"
  std::string getCameraName() const;

 private:
  const uint32_t mCameraId;
  const std::shared_ptr<
      ::aidl::android::companion::virtualcamera::IVirtualCameraCallback>
      mVirtualCameraClientCallback;

  ::aidl::android::hardware::camera::device::CameraMetadata mCameraCharacteristics;
};

}  // namespace virtualcamera
}  // namespace companion
}  // namespace android

#endif  // ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERADEVICE_H
+219 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// #define LOG_NDEBUG 0
#define LOG_TAG "VirtualCameraProvider"
#include "VirtualCameraProvider.h"

#include <atomic>
#include <memory>
#include <mutex>
#include <tuple>
#include <utility>

#include "VirtualCameraDevice.h"
#include "aidl/android/hardware/camera/common/Status.h"
#include "log/log.h"
#include "util/Util.h"

namespace android {
namespace companion {
namespace virtualcamera {

using ::aidl::android::companion::virtualcamera::IVirtualCameraCallback;
using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
using ::aidl::android::hardware::camera::common::Status;
using ::aidl::android::hardware::camera::common::VendorTagSection;
using ::aidl::android::hardware::camera::device::ICameraDevice;
using ::aidl::android::hardware::camera::provider::CameraIdAndStreamCombination;
using ::aidl::android::hardware::camera::provider::ConcurrentCameraIdCombination;
using ::aidl::android::hardware::camera::provider::ICameraProviderCallback;

// TODO(b/301023410) Make camera id range configurable / dynamic
// based on already registered devices.
std::atomic_int VirtualCameraProvider::sNextId{42};

ndk::ScopedAStatus VirtualCameraProvider::setCallback(
    const std::shared_ptr<ICameraProviderCallback>& in_callback) {
  ALOGV("%s", __func__);

  if (in_callback == nullptr) {
    return cameraStatus(Status::ILLEGAL_ARGUMENT);
  }

  {
    const std::lock_guard<std::mutex> lock(mLock);
    mCameraProviderCallback = in_callback;

    for (const auto& [cameraName, _] : mCameras) {
      auto ret = mCameraProviderCallback->cameraDeviceStatusChange(
          cameraName, CameraDeviceStatus::PRESENT);
      if (!ret.isOk()) {
        ALOGE("Failed to announce camera status change: %s",
              ret.getDescription().c_str());
      }
    }
  }
  return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus VirtualCameraProvider::getVendorTags(
    std::vector<VendorTagSection>* _aidl_return) {
  ALOGV("%s", __func__);

  if (_aidl_return == nullptr) {
    return cameraStatus(Status::ILLEGAL_ARGUMENT);
  }

  // No vendor tags supported.
  _aidl_return->clear();
  return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus VirtualCameraProvider::getCameraIdList(
    std::vector<std::string>* _aidl_return) {
  ALOGV("%s", __func__);

  if (_aidl_return == nullptr) {
    return cameraStatus(Status::ILLEGAL_ARGUMENT);
  }

  {
    const std::lock_guard<std::mutex> lock(mLock);
    _aidl_return->clear();
    _aidl_return->reserve(mCameras.size());
    for (const auto& [cameraName, _] : mCameras) {
      _aidl_return->emplace_back(cameraName);
    }
  }
  return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus VirtualCameraProvider::getCameraDeviceInterface(
    const std::string& in_cameraDeviceName,
    std::shared_ptr<ICameraDevice>* _aidl_return) {
  ALOGV("%s cameraDeviceName %s", __func__, in_cameraDeviceName.c_str());

  if (_aidl_return == nullptr) {
    return cameraStatus(Status::ILLEGAL_ARGUMENT);
  }

  {
    const std::lock_guard<std::mutex> lock(mLock);
    const auto it = mCameras.find(in_cameraDeviceName);
    *_aidl_return = (it == mCameras.end()) ? nullptr : it->second;
  }

  return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus VirtualCameraProvider::notifyDeviceStateChange(
    int64_t in_deviceState) {
  ALOGV("%s", __func__);
  (void)in_deviceState;
  return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus VirtualCameraProvider::getConcurrentCameraIds(
    std::vector<ConcurrentCameraIdCombination>* _aidl_return) {
  ALOGV("%s", __func__);
  if (_aidl_return == nullptr) {
    return cameraStatus(Status::ILLEGAL_ARGUMENT);
  }

  // No support for any concurrent combination.
  _aidl_return->clear();
  return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus VirtualCameraProvider::isConcurrentStreamCombinationSupported(
    const std::vector<CameraIdAndStreamCombination>& in_configs,
    bool* _aidl_return) {
  ALOGV("%s", __func__);
  (void)in_configs;
  if (_aidl_return == nullptr) {
    return cameraStatus(Status::ILLEGAL_ARGUMENT);
  }

  // No support for any stream combination at the moment.
  *_aidl_return = false;
  return ndk::ScopedAStatus::ok();
}

std::shared_ptr<VirtualCameraDevice> VirtualCameraProvider::createCamera(
    std::shared_ptr<IVirtualCameraCallback> virtualCameraClientCallback) {
  auto camera = ndk::SharedRefBase::make<VirtualCameraDevice>(
      sNextId++, virtualCameraClientCallback);
  std::shared_ptr<ICameraProviderCallback> callback;
  {
    const std::lock_guard<std::mutex> lock(mLock);
    if (mCameras.find(camera->getCameraName()) != mCameras.end()) {
      ALOGE("Camera with identical name already exists.");
      return nullptr;
    }
    mCameras.emplace(std::piecewise_construct,
                     std::forward_as_tuple(camera->getCameraName()),
                     std::forward_as_tuple(camera));
    callback = mCameraProviderCallback;
  }

  if (callback != nullptr) {
    auto ret = callback->cameraDeviceStatusChange(camera->getCameraName(),
                                                  CameraDeviceStatus::PRESENT);
    if (!ret.isOk()) {
      ALOGE("Failed to announce camera %s status change (PRESENT): %s",
            camera->getCameraName().c_str(), ret.getDescription().c_str());
    }
  }
  return camera;
}

std::shared_ptr<VirtualCameraDevice> VirtualCameraProvider::getCamera(
    const std::string& cameraName) {
  const std::lock_guard<std::mutex> lock(mLock);
  auto it = mCameras.find(cameraName);
  return it == mCameras.end() ? nullptr : it->second;
}

bool VirtualCameraProvider::removeCamera(const std::string& name) {
  std::shared_ptr<ICameraProviderCallback> callback;
  {
    const std::lock_guard<std::mutex> lock(mLock);
    auto it = mCameras.find(name);
    if (it == mCameras.end()) {
      ALOGE("Cannot remove camera %s: no such camera", name.c_str());
      return false;
    }
    // TODO(b/301023410) Gracefully shut down camera.
    mCameras.erase(it);
    callback = mCameraProviderCallback;
  }

  if (callback != nullptr) {
    auto ret = callback->cameraDeviceStatusChange(
        name, CameraDeviceStatus::NOT_PRESENT);
    if (!ret.isOk()) {
      ALOGE("Failed to announce camera %s status change (NOT_PRESENT): %s",
            name.c_str(), ret.getDescription().c_str());
    }
  }

  return true;
}

}  // namespace virtualcamera
}  // namespace companion
}  // namespace android
Loading