Allow to specify list of supported input configurations.

... and populate corresponding metadata entries / perform
validation based on these.

Bug: 301023410
Test: atest virtual_camera_tests
Change-Id: I66f3cf2b013d5845b6fa7429294a1ed2157318f8
diff --git a/services/camera/virtualcamera/tests/Android.bp b/services/camera/virtualcamera/tests/Android.bp
index c30779c..bc46ba0 100644
--- a/services/camera/virtualcamera/tests/Android.bp
+++ b/services/camera/virtualcamera/tests/Android.bp
@@ -15,6 +15,7 @@
         "libgmock",
     ],
     srcs: ["EglUtilTest.cc",
+           "VirtualCameraDeviceTest.cc",
            "VirtualCameraProviderTest.cc",
            "VirtualCameraRenderThreadTest.cc",
            "VirtualCameraServiceTest.cc",
diff --git a/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
new file mode 100644
index 0000000..140ae65
--- /dev/null
+++ b/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
@@ -0,0 +1,214 @@
+/*
+ * 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.
+ */
+
+#include <memory>
+
+#include "VirtualCameraDevice.h"
+#include "aidl/android/companion/virtualcamera/Format.h"
+#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
+#include "aidl/android/hardware/camera/device/CameraMetadata.h"
+#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
+#include "android/binder_interface_utils.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "log/log_main.h"
+#include "system/camera_metadata.h"
+#include "utils/Errors.h"
+
+namespace android {
+namespace companion {
+namespace virtualcamera {
+namespace {
+
+using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
+using ::aidl::android::hardware::camera::device::CameraMetadata;
+using ::aidl::android::hardware::camera::device::Stream;
+using ::aidl::android::hardware::camera::device::StreamConfiguration;
+using ::aidl::android::hardware::camera::device::StreamType;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
+using ::testing::UnorderedElementsAreArray;
+using metadata_stream_t =
+    camera_metadata_enum_android_scaler_available_stream_configurations_t;
+
+constexpr int kCameraId = 42;
+constexpr int kVgaWidth = 640;
+constexpr int kVgaHeight = 480;
+constexpr int kHdWidth = 1280;
+constexpr int kHdHeight = 720;
+
+struct AvailableStreamConfiguration {
+  const int width;
+  const int height;
+  const int pixelFormat;
+  const metadata_stream_t streamConfiguration;
+};
+
+bool operator==(const AvailableStreamConfiguration& a,
+                const AvailableStreamConfiguration& b) {
+  return a.width == b.width && a.height == b.height &&
+         a.pixelFormat == b.pixelFormat &&
+         a.streamConfiguration == b.streamConfiguration;
+}
+
+std::ostream& operator<<(std::ostream& os,
+                         const AvailableStreamConfiguration& config) {
+  os << config.width << "x" << config.height << " (pixfmt "
+     << config.pixelFormat << ", streamConfiguration "
+     << config.streamConfiguration << ")";
+  return os;
+}
+
+std::vector<AvailableStreamConfiguration> getAvailableStreamConfigurations(
+    const CameraMetadata& metadata) {
+  const camera_metadata_t* const raw =
+      reinterpret_cast<const camera_metadata_t*>(metadata.metadata.data());
+  camera_metadata_ro_entry_t entry;
+  if (find_camera_metadata_ro_entry(
+          raw, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry) !=
+      NO_ERROR) {
+    return {};
+  }
+
+  std::vector<AvailableStreamConfiguration> res;
+  for (int i = 0; i < entry.count; i += 4) {
+    res.push_back(AvailableStreamConfiguration{
+        .width = entry.data.i32[i + 1],
+        .height = entry.data.i32[i + 2],
+        .pixelFormat = entry.data.i32[i],
+        .streamConfiguration =
+            static_cast<metadata_stream_t>(entry.data.i32[i + 3])});
+  }
+  return res;
+}
+
+struct VirtualCameraConfigTestParam {
+  std::vector<SupportedStreamConfiguration> inputConfig;
+  std::vector<AvailableStreamConfiguration> expectedAvailableStreamConfigs;
+};
+
+class VirtualCameraDeviceTest
+    : public testing::TestWithParam<VirtualCameraConfigTestParam> {};
+
+TEST_P(VirtualCameraDeviceTest, cameraCharacteristicsForInputFormat) {
+  const VirtualCameraConfigTestParam& param = GetParam();
+  std::shared_ptr<VirtualCameraDevice> camera =
+      ndk::SharedRefBase::make<VirtualCameraDevice>(
+          kCameraId, param.inputConfig, /*virtualCameraClientCallback=*/nullptr);
+
+  CameraMetadata metadata;
+  ASSERT_TRUE(camera->getCameraCharacteristics(&metadata).isOk());
+  EXPECT_THAT(getAvailableStreamConfigurations(metadata),
+              UnorderedElementsAreArray(param.expectedAvailableStreamConfigs));
+
+  // Configuration needs to succeed for every available stream configuration
+  for (const AvailableStreamConfiguration& config :
+       param.expectedAvailableStreamConfigs) {
+    StreamConfiguration configuration{
+        .streams = std::vector<Stream>{Stream{
+            .streamType = StreamType::OUTPUT,
+            .width = config.width,
+            .height = config.height,
+            .format = static_cast<PixelFormat>(config.pixelFormat),
+        }}};
+    bool aidl_ret;
+    ASSERT_TRUE(
+        camera->isStreamCombinationSupported(configuration, &aidl_ret).isOk());
+    EXPECT_TRUE(aidl_ret);
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    cameraCharacteristicsForInputFormat, VirtualCameraDeviceTest,
+    testing::Values(
+        VirtualCameraConfigTestParam{
+            .inputConfig = {SupportedStreamConfiguration{
+                .width = kVgaWidth,
+                .height = kVgaHeight,
+                .pixelFormat = Format::YUV_420_888}},
+            .expectedAvailableStreamConfigs =
+                {AvailableStreamConfiguration{
+                     .width = kVgaWidth,
+                     .height = kVgaHeight,
+                     .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,
+                     .streamConfiguration =
+                         ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT},
+                 AvailableStreamConfiguration{
+                     .width = kVgaWidth,
+                     .height = kVgaHeight,
+                     .pixelFormat =
+                         ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
+                     .streamConfiguration =
+                         ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT},
+                 AvailableStreamConfiguration{
+                     .width = kVgaWidth,
+                     .height = kVgaHeight,
+                     .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB,
+                     .streamConfiguration =
+                         ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT}}},
+        VirtualCameraConfigTestParam{
+            .inputConfig = {SupportedStreamConfiguration{
+                                .width = kVgaWidth,
+                                .height = kVgaHeight,
+                                .pixelFormat = Format::YUV_420_888},
+                            SupportedStreamConfiguration{
+                                .width = kHdWidth,
+                                .height = kHdHeight,
+                                .pixelFormat = Format::YUV_420_888}},
+            .expectedAvailableStreamConfigs = {
+                AvailableStreamConfiguration{
+                    .width = kVgaWidth,
+                    .height = kVgaHeight,
+                    .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,
+                    .streamConfiguration =
+                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT},
+                AvailableStreamConfiguration{
+                    .width = kVgaWidth,
+                    .height = kVgaHeight,
+                    .pixelFormat =
+                        ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
+                    .streamConfiguration =
+                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT},
+                AvailableStreamConfiguration{
+                    .width = kVgaWidth,
+                    .height = kVgaHeight,
+                    .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB,
+                    .streamConfiguration =
+                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT},
+                AvailableStreamConfiguration{
+                    .width = kHdWidth,
+                    .height = kHdHeight,
+                    .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,
+                    .streamConfiguration =
+                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT},
+                AvailableStreamConfiguration{
+                    .width = kHdWidth,
+                    .height = kHdHeight,
+                    .pixelFormat =
+                        ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
+                    .streamConfiguration =
+                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT},
+                AvailableStreamConfiguration{
+                    .width = kHdWidth,
+                    .height = kHdHeight,
+                    .pixelFormat = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB,
+                    .streamConfiguration =
+                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT}}}));
+
+}  // namespace
+}  // namespace virtualcamera
+}  // namespace companion
+}  // namespace android
diff --git a/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc b/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
index 03fc2c2..615a77c 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
@@ -32,6 +32,8 @@
 namespace virtualcamera {
 namespace {
 
+using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
 using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
 using ::aidl::android::hardware::camera::common::Status;
 using ::aidl::android::hardware::camera::common::TorchModeStatus;
@@ -45,6 +47,8 @@
 using ::testing::Not;
 using ::testing::Return;
 
+constexpr int kVgaWidth = 640;
+constexpr int kVgaHeight = 480;
 constexpr char kVirtualCameraNameRegex[] =
     "device@[0-9]+\\.[0-9]+/virtual/[0-9]+";
 
@@ -75,6 +79,10 @@
   std::shared_ptr<VirtualCameraProvider> mCameraProvider;
   std::shared_ptr<MockCameraProviderCallback> mMockCameraProviderCallback =
       ndk::SharedRefBase::make<MockCameraProviderCallback>();
+  std::vector<SupportedStreamConfiguration> mInputConfigs = {
+      SupportedStreamConfiguration{.width = kVgaWidth,
+                                   .height = kVgaHeight,
+                                   .pixelFormat = Format::YUV_420_888}};
 };
 
 TEST_F(VirtualCameraProviderTest, SetNullCameraCallbackFails) {
@@ -100,7 +108,8 @@
       .WillOnce(Return(ndk::ScopedAStatus::ok()));
 
   ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
-  std::shared_ptr<VirtualCameraDevice> camera = mCameraProvider->createCamera();
+  std::shared_ptr<VirtualCameraDevice> camera =
+      mCameraProvider->createCamera(mInputConfigs);
   EXPECT_THAT(camera, Not(IsNull()));
   EXPECT_THAT(camera->getCameraName(), MatchesRegex(kVirtualCameraNameRegex));
 
@@ -117,7 +126,8 @@
               cameraDeviceStatusChange(_, CameraDeviceStatus::PRESENT))
       .WillOnce(Return(ndk::ScopedAStatus::ok()));
 
-  std::shared_ptr<VirtualCameraDevice> camera = mCameraProvider->createCamera();
+  std::shared_ptr<VirtualCameraDevice> camera =
+      mCameraProvider->createCamera(mInputConfigs);
   ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
 
   // Created camera should be in the list of cameras.
@@ -128,7 +138,8 @@
 
 TEST_F(VirtualCameraProviderTest, RemoveCamera) {
   ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
-  std::shared_ptr<VirtualCameraDevice> camera = mCameraProvider->createCamera();
+  std::shared_ptr<VirtualCameraDevice> camera =
+      mCameraProvider->createCamera(mInputConfigs);
 
   EXPECT_CALL(*mMockCameraProviderCallback,
               cameraDeviceStatusChange(Eq(camera->getCameraName()),
@@ -144,7 +155,8 @@
 
 TEST_F(VirtualCameraProviderTest, RemoveNonExistingCamera) {
   ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
-  std::shared_ptr<VirtualCameraDevice> camera = mCameraProvider->createCamera();
+  std::shared_ptr<VirtualCameraDevice> camera =
+      mCameraProvider->createCamera(mInputConfigs);
 
   // Removing non-existing camera should fail.
   const std::string cameraName = "DefinitelyNoTCamera";
diff --git a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
index 4fd0b3b..04349b1 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
@@ -37,6 +37,7 @@
 namespace {
 
 using ::aidl::android::companion::virtualcamera::BnVirtualCameraCallback;
+using ::aidl::android::companion::virtualcamera::Format;
 using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
 using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
 using ::aidl::android::hardware::camera::common::TorchModeStatus;
@@ -51,8 +52,19 @@
 using ::testing::Not;
 using ::testing::SizeIs;
 
+constexpr int kVgaWidth = 640;
+constexpr int kVgaHeight = 480;
+
 const VirtualCameraConfiguration kEmptyVirtualCameraConfiguration;
 
+VirtualCameraConfiguration createConfiguration(const int width, const int height,
+                                               const Format format) {
+  VirtualCameraConfiguration configuration;
+  configuration.supportedStreamConfigs.push_back(
+      {.width = width, .height = height, .pixelFormat = format});
+  return configuration;
+}
+
 class MockCameraProviderCallback : public BnCameraProviderCallback {
  public:
   MOCK_METHOD(ndk::ScopedAStatus, cameraDeviceStatusChange,
@@ -89,7 +101,7 @@
 
     ASSERT_TRUE(mCameraService
                     ->registerCamera(mNdkOwnerToken,
-                                     kEmptyVirtualCameraConfiguration, &aidlRet)
+                                     mVgaYUV420OnlyConfiguration, &aidlRet)
                     .isOk());
     ASSERT_TRUE(aidlRet);
   }
@@ -106,6 +118,12 @@
         Eq(NO_ERROR));
   }
 
+  std::vector<std::string> getCameraIds() {
+    std::vector<std::string> cameraIds;
+    EXPECT_TRUE(mCameraProvider->getCameraIdList(&cameraIds).isOk());
+    return cameraIds;
+  }
+
  protected:
   std::shared_ptr<VirtualCameraService> mCameraService;
   std::shared_ptr<VirtualCameraProvider> mCameraProvider;
@@ -116,6 +134,9 @@
   ndk::SpAIBinder mNdkOwnerToken;
 
   int mDevNullFd;
+
+  VirtualCameraConfiguration mVgaYUV420OnlyConfiguration =
+      createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888);
 };
 
 TEST_F(VirtualCameraServiceTest, RegisterCameraSucceeds) {
@@ -125,10 +146,11 @@
 
   ASSERT_TRUE(
       mCameraService
-          ->registerCamera(ndkToken, kEmptyVirtualCameraConfiguration, &aidlRet)
+          ->registerCamera(ndkToken, mVgaYUV420OnlyConfiguration, &aidlRet)
           .isOk());
 
   EXPECT_TRUE(aidlRet);
+  EXPECT_THAT(getCameraIds(), SizeIs(1));
 }
 
 TEST_F(VirtualCameraServiceTest, RegisterCameraTwiceSecondReturnsFalse) {
@@ -136,10 +158,67 @@
   bool aidlRet;
 
   ASSERT_TRUE(mCameraService
-                  ->registerCamera(mNdkOwnerToken,
-                                   kEmptyVirtualCameraConfiguration, &aidlRet)
+                  ->registerCamera(mNdkOwnerToken, mVgaYUV420OnlyConfiguration,
+                                   &aidlRet)
                   .isOk());
   EXPECT_FALSE(aidlRet);
+  EXPECT_THAT(getCameraIds(), SizeIs(1));
+}
+
+TEST_F(VirtualCameraServiceTest, EmptyConfigurationFails) {
+  bool aidlRet;
+
+  ASSERT_FALSE(mCameraService
+                   ->registerCamera(mNdkOwnerToken,
+                                    kEmptyVirtualCameraConfiguration, &aidlRet)
+                   .isOk());
+  EXPECT_FALSE(aidlRet);
+  EXPECT_THAT(getCameraIds(), IsEmpty());
+}
+
+TEST_F(VirtualCameraServiceTest, ConfigurationWithUnsupportedPixelFormatFails) {
+  bool aidlRet;
+
+  VirtualCameraConfiguration config =
+      createConfiguration(kVgaWidth, kVgaHeight, Format::UNKNOWN);
+
+  ASSERT_FALSE(
+      mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
+  EXPECT_FALSE(aidlRet);
+  EXPECT_THAT(getCameraIds(), IsEmpty());
+}
+
+TEST_F(VirtualCameraServiceTest, ConfigurationWithTooHighResFails) {
+  bool aidlRet;
+  VirtualCameraConfiguration config =
+      createConfiguration(1000000, 1000000, Format::YUV_420_888);
+
+  ASSERT_FALSE(
+      mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
+  EXPECT_FALSE(aidlRet);
+  EXPECT_THAT(getCameraIds(), IsEmpty());
+}
+
+TEST_F(VirtualCameraServiceTest, ConfigurationWithUnalignedResolutionFails) {
+  bool aidlRet;
+  VirtualCameraConfiguration config =
+      createConfiguration(641, 481, Format::YUV_420_888);
+
+  ASSERT_FALSE(
+      mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
+  EXPECT_FALSE(aidlRet);
+  EXPECT_THAT(getCameraIds(), IsEmpty());
+}
+
+TEST_F(VirtualCameraServiceTest, ConfigurationWithNegativeResolutionFails) {
+  bool aidlRet;
+  VirtualCameraConfiguration config =
+      createConfiguration(-1, kVgaHeight, Format::YUV_420_888);
+
+  ASSERT_FALSE(
+      mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
+  EXPECT_FALSE(aidlRet);
+  EXPECT_THAT(getCameraIds(), IsEmpty());
 }
 
 TEST_F(VirtualCameraServiceTest, GetCamera) {
@@ -191,13 +270,13 @@
 TEST_F(VirtualCameraServiceTest, TestCameraShellCmd) {
   execute_shell_command("enable_test_camera");
 
-  std::vector<std::string> cameraIds;
-  EXPECT_TRUE(mCameraProvider->getCameraIdList(&cameraIds).isOk());
-  EXPECT_THAT(cameraIds, SizeIs(1));
+  std::vector<std::string> cameraIdsAfterEnable = getCameraIds();
+  EXPECT_THAT(cameraIdsAfterEnable, SizeIs(1));
 
   execute_shell_command("disable_test_camera");
-  EXPECT_TRUE(mCameraProvider->getCameraIdList(&cameraIds).isOk());
-  EXPECT_THAT(cameraIds, IsEmpty());
+
+  std::vector<std::string> cameraIdsAfterDisable = getCameraIds();
+  EXPECT_THAT(cameraIdsAfterDisable, IsEmpty());
 }
 
 }  // namespace
diff --git a/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc b/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
index 5da080b..0bc5210 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
@@ -17,9 +17,11 @@
 #include <cstdint>
 #include <memory>
 
+#include "VirtualCameraDevice.h"
 #include "VirtualCameraSession.h"
 #include "aidl/android/companion/virtualcamera/BnVirtualCameraCallback.h"
 #include "aidl/android/companion/virtualcamera/IVirtualCameraCallback.h"
+#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
 #include "aidl/android/hardware/camera/device/BnCameraDeviceCallback.h"
 #include "aidl/android/hardware/camera/device/StreamConfiguration.h"
 #include "aidl/android/hardware/graphics/common/PixelFormat.h"
@@ -37,10 +39,11 @@
 constexpr int kWidth = 640;
 constexpr int kHeight = 480;
 constexpr int kStreamId = 0;
-const std::string kCameraName = "virtual_camera";
+constexpr int kCameraId = 42;
 
 using ::aidl::android::companion::virtualcamera::BnVirtualCameraCallback;
 using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
 using ::aidl::android::hardware::camera::device::BnCameraDeviceCallback;
 using ::aidl::android::hardware::camera::device::BufferRequest;
 using ::aidl::android::hardware::camera::device::BufferRequestStatus;
@@ -99,8 +102,15 @@
         ndk::SharedRefBase::make<MockCameraDeviceCallback>();
     mMockVirtualCameraClientCallback =
         ndk::SharedRefBase::make<MockVirtualCameraCallback>();
+    mVirtualCameraDevice = ndk::SharedRefBase::make<VirtualCameraDevice>(
+        kCameraId,
+        std::vector<SupportedStreamConfiguration>{
+            SupportedStreamConfiguration{.width = kWidth,
+                                         .height = kHeight,
+                                         .pixelFormat = Format::YUV_420_888}},
+        mMockVirtualCameraClientCallback);
     mVirtualCameraSession = ndk::SharedRefBase::make<VirtualCameraSession>(
-        kCameraName, mMockCameraDeviceCallback,
+        *mVirtualCameraDevice, mMockCameraDeviceCallback,
         mMockVirtualCameraClientCallback);
 
     ON_CALL(*mMockVirtualCameraClientCallback, onStreamConfigured)
@@ -112,6 +122,7 @@
  protected:
   std::shared_ptr<MockCameraDeviceCallback> mMockCameraDeviceCallback;
   std::shared_ptr<MockVirtualCameraCallback> mMockVirtualCameraClientCallback;
+  std::shared_ptr<VirtualCameraDevice> mVirtualCameraDevice;
   std::shared_ptr<VirtualCameraSession> mVirtualCameraSession;
 };