blob: be065234659b8da8631eef81e6cf58a5f7054a3c [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#include <cstdint>
18#include <memory>
19
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010020#include "VirtualCameraDevice.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010021#include "VirtualCameraSession.h"
22#include "aidl/android/companion/virtualcamera/BnVirtualCameraCallback.h"
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010023#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
Biswarup Pal6152a302023-12-19 12:44:09 +000024#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +010025#include "aidl/android/hardware/camera/common/Status.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010026#include "aidl/android/hardware/camera/device/BnCameraDeviceCallback.h"
27#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
28#include "aidl/android/hardware/graphics/common/PixelFormat.h"
29#include "android/binder_auto_utils.h"
30#include "android/binder_interface_utils.h"
31#include "gmock/gmock.h"
32#include "gtest/gtest.h"
33#include "util/MetadataBuilder.h"
34
35namespace android {
36namespace companion {
37namespace virtualcamera {
38namespace {
39
40constexpr int kWidth = 640;
41constexpr int kHeight = 480;
Biswarup Pal6152a302023-12-19 12:44:09 +000042constexpr int kMaxFps = 30;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010043constexpr int kStreamId = 0;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010044constexpr int kCameraId = 42;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010045
46using ::aidl::android::companion::virtualcamera::BnVirtualCameraCallback;
47using ::aidl::android::companion::virtualcamera::Format;
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 Sebechlebsky0bb5e092023-12-08 16:17:54 +010052using ::aidl::android::hardware::camera::common::Status;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010053using ::aidl::android::hardware::camera::device::BnCameraDeviceCallback;
54using ::aidl::android::hardware::camera::device::BufferRequest;
55using ::aidl::android::hardware::camera::device::BufferRequestStatus;
56using ::aidl::android::hardware::camera::device::CaptureRequest;
57using ::aidl::android::hardware::camera::device::CaptureResult;
58using ::aidl::android::hardware::camera::device::HalStream;
59using ::aidl::android::hardware::camera::device::NotifyMsg;
60using ::aidl::android::hardware::camera::device::Stream;
61using ::aidl::android::hardware::camera::device::StreamBuffer;
62using ::aidl::android::hardware::camera::device::StreamBufferRet;
63using ::aidl::android::hardware::camera::device::StreamConfiguration;
64using ::aidl::android::hardware::graphics::common::PixelFormat;
65using ::aidl::android::view::Surface;
66using ::testing::_;
67using ::testing::ElementsAre;
68using ::testing::Eq;
69using ::testing::Return;
70using ::testing::SizeIs;
71
72Stream createStream(int streamId, int width, int height, PixelFormat format) {
73 Stream s;
74 s.id = streamId;
75 s.width = width;
76 s.height = height;
77 s.format = format;
78 return s;
79}
80
81class MockCameraDeviceCallback : public BnCameraDeviceCallback {
82 public:
83 MOCK_METHOD(ndk::ScopedAStatus, notify, (const std::vector<NotifyMsg>&),
84 (override));
85 MOCK_METHOD(ndk::ScopedAStatus, processCaptureResult,
86 (const std::vector<CaptureResult>&), (override));
87 MOCK_METHOD(ndk::ScopedAStatus, requestStreamBuffers,
88 (const std::vector<BufferRequest>&, std::vector<StreamBufferRet>*,
89 BufferRequestStatus*),
90 (override));
91 MOCK_METHOD(ndk::ScopedAStatus, returnStreamBuffers,
92 (const std::vector<StreamBuffer>&), (override));
93};
94
95class MockVirtualCameraCallback : public BnVirtualCameraCallback {
96 public:
97 MOCK_METHOD(ndk::ScopedAStatus, onStreamConfigured,
98 (int, const Surface&, int32_t, int32_t, Format), (override));
99 MOCK_METHOD(ndk::ScopedAStatus, onProcessCaptureRequest, (int, int),
100 (override));
101 MOCK_METHOD(ndk::ScopedAStatus, onStreamClosed, (int), (override));
102};
103
104class VirtualCameraSessionTest : public ::testing::Test {
105 public:
106 void SetUp() override {
107 mMockCameraDeviceCallback =
108 ndk::SharedRefBase::make<MockCameraDeviceCallback>();
109 mMockVirtualCameraClientCallback =
110 ndk::SharedRefBase::make<MockVirtualCameraCallback>();
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100111 mVirtualCameraDevice = ndk::SharedRefBase::make<VirtualCameraDevice>(
Biswarup Pal6152a302023-12-19 12:44:09 +0000112 kCameraId, VirtualCameraConfiguration{
113 .supportedStreamConfigs = {SupportedStreamConfiguration{
114 .width = kWidth,
115 .height = kHeight,
116 .pixelFormat = Format::YUV_420_888,
117 .maxFps = kMaxFps}},
118 .virtualCameraCallback = nullptr,
Biswarup Pal112458f2023-12-28 19:50:17 +0000119 .sensorOrientation = SensorOrientation::ORIENTATION_0,
120 .lensFacing = LensFacing::FRONT});
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100121 mVirtualCameraSession = ndk::SharedRefBase::make<VirtualCameraSession>(
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100122 mVirtualCameraDevice, mMockCameraDeviceCallback,
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100123 mMockVirtualCameraClientCallback);
124
Jan Sebechlebsky85a2aef2023-11-29 10:35:55 +0100125 // Explicitly defining default actions below to prevent gmock from
126 // default-constructing ndk::ScopedAStatus, because default-constructed
127 // status wraps nullptr AStatus and causes crash when attempting to print
128 // it in gtest report.
129 ON_CALL(*mMockCameraDeviceCallback, notify)
130 .WillByDefault(ndk::ScopedAStatus::ok);
131 ON_CALL(*mMockCameraDeviceCallback, processCaptureResult)
132 .WillByDefault(ndk::ScopedAStatus::ok);
133 ON_CALL(*mMockCameraDeviceCallback, requestStreamBuffers)
134 .WillByDefault(ndk::ScopedAStatus::ok);
135 ON_CALL(*mMockCameraDeviceCallback, returnStreamBuffers)
136 .WillByDefault(ndk::ScopedAStatus::ok);
137
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100138 ON_CALL(*mMockVirtualCameraClientCallback, onStreamConfigured)
139 .WillByDefault(ndk::ScopedAStatus::ok);
140 ON_CALL(*mMockVirtualCameraClientCallback, onProcessCaptureRequest)
141 .WillByDefault(ndk::ScopedAStatus::ok);
Jan Sebechlebsky85a2aef2023-11-29 10:35:55 +0100142 ON_CALL(*mMockVirtualCameraClientCallback, onStreamClosed)
143 .WillByDefault(ndk::ScopedAStatus::ok);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100144 }
145
146 protected:
147 std::shared_ptr<MockCameraDeviceCallback> mMockCameraDeviceCallback;
148 std::shared_ptr<MockVirtualCameraCallback> mMockVirtualCameraClientCallback;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100149 std::shared_ptr<VirtualCameraDevice> mVirtualCameraDevice;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100150 std::shared_ptr<VirtualCameraSession> mVirtualCameraSession;
151};
152
153TEST_F(VirtualCameraSessionTest, ConfigureTriggersClientConfigureCallback) {
154 PixelFormat format = PixelFormat::YCBCR_420_888;
155 StreamConfiguration streamConfiguration;
156 streamConfiguration.streams = {
157 createStream(kStreamId, kWidth, kHeight, format)};
158 std::vector<HalStream> halStreams;
159 EXPECT_CALL(
160 *mMockVirtualCameraClientCallback,
161 onStreamConfigured(kStreamId, _, kWidth, kHeight, Format::YUV_420_888));
162
163 ASSERT_TRUE(
164 mVirtualCameraSession->configureStreams(streamConfiguration, &halStreams)
165 .isOk());
166
167 EXPECT_THAT(halStreams, SizeIs(streamConfiguration.streams.size()));
168 EXPECT_THAT(mVirtualCameraSession->getStreamIds(), ElementsAre(0));
169}
170
171TEST_F(VirtualCameraSessionTest, SecondConfigureDropsUnreferencedStreams) {
172 PixelFormat format = PixelFormat::YCBCR_420_888;
173 StreamConfiguration streamConfiguration;
174 std::vector<HalStream> halStreams;
175
176 streamConfiguration.streams = {createStream(0, kWidth, kHeight, format),
177 createStream(1, kWidth, kHeight, format),
178 createStream(2, kWidth, kHeight, format)};
179 ASSERT_TRUE(
180 mVirtualCameraSession->configureStreams(streamConfiguration, &halStreams)
181 .isOk());
182
183 EXPECT_THAT(mVirtualCameraSession->getStreamIds(), ElementsAre(0, 1, 2));
184
185 streamConfiguration.streams = {createStream(0, kWidth, kHeight, format),
186 createStream(2, kWidth, kHeight, format),
187 createStream(3, kWidth, kHeight, format)};
188 ASSERT_TRUE(
189 mVirtualCameraSession->configureStreams(streamConfiguration, &halStreams)
190 .isOk());
191
192 EXPECT_THAT(mVirtualCameraSession->getStreamIds(), ElementsAre(0, 2, 3));
193}
194
195TEST_F(VirtualCameraSessionTest, CloseTriggersClientTerminateCallback) {
196 EXPECT_CALL(*mMockVirtualCameraClientCallback, onStreamClosed(kStreamId))
197 .WillOnce(Return(ndk::ScopedAStatus::ok()));
198
199 ASSERT_TRUE(mVirtualCameraSession->close().isOk());
200}
201
Jan Sebechlebskyb0d8cab2023-11-28 10:55:04 +0100202TEST_F(VirtualCameraSessionTest, FlushBeforeConfigure) {
203 // Flush request coming before the configure request finished
204 // (so potentially the thread is not yet running) should be
205 // gracefully handled.
206
207 EXPECT_TRUE(mVirtualCameraSession->flush().isOk());
208}
209
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100210TEST_F(VirtualCameraSessionTest, onProcessCaptureRequestTriggersClientCallback) {
211 StreamConfiguration streamConfiguration;
212 streamConfiguration.streams = {
213 createStream(kStreamId, kWidth, kHeight, PixelFormat::YCBCR_420_888)};
214 std::vector<CaptureRequest> requests(1);
215 requests[0].frameNumber = 42;
216 requests[0].settings = *(
217 MetadataBuilder().setControlAfMode(ANDROID_CONTROL_AF_MODE_AUTO).build());
218
219 std::vector<HalStream> halStreams;
220 ASSERT_TRUE(
221 mVirtualCameraSession->configureStreams(streamConfiguration, &halStreams)
222 .isOk());
223
224 EXPECT_CALL(*mMockVirtualCameraClientCallback,
225 onProcessCaptureRequest(kStreamId, requests[0].frameNumber))
226 .WillOnce(Return(ndk::ScopedAStatus::ok()));
227 int32_t aidlReturn = 0;
228 ASSERT_TRUE(mVirtualCameraSession
229 ->processCaptureRequest(requests, /*in_cachesToRemove=*/{},
230 &aidlReturn)
231 .isOk());
232 EXPECT_THAT(aidlReturn, Eq(requests.size()));
233}
234
Jan Sebechlebsky0bb5e092023-12-08 16:17:54 +0100235TEST_F(VirtualCameraSessionTest, configureAfterCameraRelease) {
236 StreamConfiguration streamConfiguration;
237 streamConfiguration.streams = {
238 createStream(kStreamId, kWidth, kHeight, PixelFormat::YCBCR_420_888)};
239 std::vector<HalStream> halStreams;
240
241 // Release virtual camera.
242 mVirtualCameraDevice.reset();
243
244 // Expect configuration attempt returns CAMERA_DISCONNECTED service specific code.
245 EXPECT_THAT(
246 mVirtualCameraSession->configureStreams(streamConfiguration, &halStreams)
247 .getServiceSpecificError(),
248 Eq(static_cast<int32_t>(Status::CAMERA_DISCONNECTED)));
249}
250
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100251} // namespace
252} // namespace virtualcamera
253} // namespace companion
254} // namespace android