blob: 8afd9010563eb5b122fffc700ac6f1264a4881e0 [file] [log] [blame]
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +01001/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
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
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010018#define LOG_TAG "VirtualCameraService"
19#include "VirtualCameraService.h"
20
21#include <cinttypes>
22#include <cstdint>
23#include <cstdio>
24#include <memory>
25#include <mutex>
26
27#include "VirtualCameraDevice.h"
28#include "VirtualCameraProvider.h"
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010029#include "aidl/android/companion/virtualcamera/Format.h"
30#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010031#include "android/binder_auto_utils.h"
32#include "android/binder_libbinder.h"
33#include "binder/Status.h"
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010034#include "util/Util.h"
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010035
36using ::android::binder::Status;
37
38namespace android {
39namespace companion {
40namespace virtualcamera {
41
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010042using ::aidl::android::companion::virtualcamera::Format;
43using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010044using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
45
46namespace {
47
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010048constexpr int kVgaWidth = 640;
49constexpr int kVgaHeight = 480;
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010050constexpr char kEnableTestCameraCmd[] = "enable_test_camera";
51constexpr char kDisableTestCameraCmd[] = "disable_test_camera";
52constexpr char kShellCmdHelp[] = R"(
53Available commands:
54 * enable_test_camera
55 * disable_test_camera
56)";
57
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010058ndk::ScopedAStatus validateConfiguration(
59 const VirtualCameraConfiguration& configuration) {
60 if (configuration.supportedStreamConfigs.empty()) {
61 ALOGE("%s: No supported input configuration specified", __func__);
62 return ndk::ScopedAStatus::fromServiceSpecificError(
63 Status::EX_ILLEGAL_ARGUMENT);
64 }
65
66 for (const SupportedStreamConfiguration& config :
67 configuration.supportedStreamConfigs) {
68 if (!isFormatSupportedForInput(config.width, config.height,
69 config.pixelFormat)) {
70 ALOGE("%s: Requested unsupported input format: %d x %d (%d)", __func__,
71 config.width, config.height, static_cast<int>(config.pixelFormat));
72 return ndk::ScopedAStatus::fromServiceSpecificError(
73 Status::EX_ILLEGAL_ARGUMENT);
74 }
75 }
76 return ndk::ScopedAStatus::ok();
77}
78
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010079} // namespace
80
81VirtualCameraService::VirtualCameraService(
82 std::shared_ptr<VirtualCameraProvider> virtualCameraProvider)
83 : mVirtualCameraProvider(virtualCameraProvider) {
84}
85
86ndk::ScopedAStatus VirtualCameraService::registerCamera(
87 const ::ndk::SpAIBinder& token,
88 const VirtualCameraConfiguration& configuration, bool* _aidl_return) {
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +010089 if (_aidl_return == nullptr) {
90 return ndk::ScopedAStatus::fromServiceSpecificError(
91 Status::EX_ILLEGAL_ARGUMENT);
92 }
93 *_aidl_return = true;
94
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +010095 auto status = validateConfiguration(configuration);
96 if (!status.isOk()) {
97 *_aidl_return = false;
98 return status;
99 }
100
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100101 std::lock_guard lock(mLock);
102 if (mTokenToCameraName.find(token) != mTokenToCameraName.end()) {
103 ALOGE(
104 "Attempt to register camera corresponding to already registered binder "
105 "token: "
106 "0x%" PRIxPTR,
107 reinterpret_cast<uintptr_t>(token.get()));
108 *_aidl_return = false;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100109 return ndk::ScopedAStatus::ok();
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100110 }
111
112 // TODO(b/301023410) Validate configuration and pass it to the camera.
113 std::shared_ptr<VirtualCameraDevice> camera =
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100114 mVirtualCameraProvider->createCamera(configuration.supportedStreamConfigs,
115 configuration.virtualCameraCallback);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100116 if (camera == nullptr) {
117 ALOGE("Failed to create camera for binder token 0x%" PRIxPTR,
118 reinterpret_cast<uintptr_t>(token.get()));
119 *_aidl_return = false;
120 return ndk::ScopedAStatus::fromServiceSpecificError(
121 Status::EX_SERVICE_SPECIFIC);
122 }
123
124 mTokenToCameraName[token] = camera->getCameraName();
125 return ndk::ScopedAStatus::ok();
126}
127
128ndk::ScopedAStatus VirtualCameraService::unregisterCamera(
129 const ::ndk::SpAIBinder& token) {
130 std::lock_guard lock(mLock);
131
132 auto it = mTokenToCameraName.find(token);
133 if (it == mTokenToCameraName.end()) {
134 ALOGE(
135 "Attempt to unregister camera corresponding to unknown binder token: "
136 "0x%" PRIxPTR,
137 reinterpret_cast<uintptr_t>(token.get()));
138 return ndk::ScopedAStatus::ok();
139 }
140
141 mVirtualCameraProvider->removeCamera(it->second);
142
143 return ndk::ScopedAStatus::ok();
144}
145
146std::shared_ptr<VirtualCameraDevice> VirtualCameraService::getCamera(
147 const ::ndk::SpAIBinder& token) {
148 if (token == nullptr) {
149 return nullptr;
150 }
151
152 std::lock_guard lock(mLock);
153 auto it = mTokenToCameraName.find(token);
154 if (it == mTokenToCameraName.end()) {
155 return nullptr;
156 }
157
158 return mVirtualCameraProvider->getCamera(it->second);
159}
160
161binder_status_t VirtualCameraService::handleShellCommand(int in, int out,
162 int err,
163 const char** args,
164 uint32_t numArgs) {
165 if (numArgs <= 0) {
166 dprintf(out, kShellCmdHelp);
167 }
168
169 if (args == nullptr || args[0] == nullptr) {
170 return STATUS_BAD_VALUE;
171 }
172 const char* const cmd = args[0];
173 if (strcmp(kEnableTestCameraCmd, cmd) == 0) {
174 enableTestCameraCmd(in, err);
175 } else if (strcmp(kDisableTestCameraCmd, cmd) == 0) {
176 disableTestCameraCmd(in);
177 } else {
178 dprintf(out, kShellCmdHelp);
179 }
180
181 fsync(out);
182 return STATUS_OK;
183}
184
185void VirtualCameraService::enableTestCameraCmd(const int out, const int err) {
186 if (mTestCameraToken != nullptr) {
187 dprintf(out, "Test camera is already enabled (%s).",
188 getCamera(mTestCameraToken)->getCameraName().c_str());
189 return;
190 }
191
192 sp<BBinder> token = sp<BBinder>::make();
193 mTestCameraToken.set(AIBinder_fromPlatformBinder(token));
194
195 bool ret;
Jan Sebechlebsky3b478c42023-11-23 13:15:56 +0100196 VirtualCameraConfiguration configuration;
197 configuration.supportedStreamConfigs.push_back(
198 {.width = kVgaWidth, .height = kVgaHeight, Format::YUV_420_888});
199 registerCamera(mTestCameraToken, configuration, &ret);
Jan Sebechlebsky5cb39962023-11-22 17:33:07 +0100200 if (ret) {
201 dprintf(out, "Successfully registered test camera %s",
202 getCamera(mTestCameraToken)->getCameraName().c_str());
203 } else {
204 dprintf(err, "Failed to create test camera");
205 }
206}
207
208void VirtualCameraService::disableTestCameraCmd(const int out) {
209 if (mTestCameraToken == nullptr) {
210 dprintf(out, "Test camera is not registered.");
211 }
212 unregisterCamera(mTestCameraToken);
213 mTestCameraToken.set(nullptr);
214}
215
216} // namespace virtualcamera
217} // namespace companion
218} // namespace android