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