1 /*
2 * Copyright 2021 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 #include "StreamHandler.h"
18
19 #include <aidl/android/hardware/automotive/evs/EvsEventType.h>
20 #include <aidl/android/hardware/automotive/evs/EvsResult.h>
21 #include <aidl/android/hardware/common/NativeHandle.h>
22 #include <android-base/chrono_utils.h>
23 #include <android-base/logging.h>
24 #include <android/hardware_buffer.h>
25 #include <android/hardware_buffer_jni.h>
26 #include <vndk/hardware_buffer.h>
27
28 namespace {
29
30 using ::aidl::android::hardware::automotive::evs::BufferDesc;
31 using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
32 using ::aidl::android::hardware::automotive::evs::EvsEventType;
33 using ::aidl::android::hardware::automotive::evs::EvsResult;
34 using ::aidl::android::hardware::automotive::evs::IEvsCamera;
35 using ::aidl::android::hardware::common::NativeHandle;
36 using ::aidl::android::hardware::graphics::common::HardwareBuffer;
37 using ::android::base::ScopedLockAssertion;
38
dupNativeHandle(const NativeHandle & handle,bool doDup)39 NativeHandle dupNativeHandle(const NativeHandle& handle, bool doDup) {
40 NativeHandle dup;
41
42 dup.fds = std::vector<::ndk::ScopedFileDescriptor>(handle.fds.size());
43 if (!doDup) {
44 for (auto i = 0; i < handle.fds.size(); ++i) {
45 dup.fds.at(i).set(handle.fds[i].get());
46 }
47 } else {
48 for (auto i = 0; i < handle.fds.size(); ++i) {
49 dup.fds[i] = std::move(handle.fds[i].dup());
50 }
51 }
52 dup.ints = handle.ints;
53
54 return std::move(dup);
55 }
56
dupHardwareBuffer(const HardwareBuffer & buffer,bool doDup)57 HardwareBuffer dupHardwareBuffer(const HardwareBuffer& buffer, bool doDup) {
58 HardwareBuffer dup = {
59 .description = buffer.description,
60 .handle = dupNativeHandle(buffer.handle, doDup),
61 };
62
63 return std::move(dup);
64 }
65
dupBufferDesc(const BufferDesc & src,bool doDup)66 BufferDesc dupBufferDesc(const BufferDesc& src, bool doDup) {
67 BufferDesc dup = {
68 .buffer = dupHardwareBuffer(src.buffer, doDup),
69 .pixelSizeBytes = src.pixelSizeBytes,
70 .bufferId = src.bufferId,
71 .deviceId = src.deviceId,
72 .timestamp = src.timestamp,
73 .metadata = src.metadata,
74 };
75
76 return std::move(dup);
77 }
78
79 } // namespace
80
81 namespace android::automotive::evs {
82
StreamHandler(const std::shared_ptr<IEvsCamera> & camObj,EvsServiceCallback * callback,int maxNumFramesInFlight)83 StreamHandler::StreamHandler(const std::shared_ptr<IEvsCamera>& camObj,
84 EvsServiceCallback* callback, int maxNumFramesInFlight) :
85 mEvsCamera(camObj), mCallback(callback), mMaxNumFramesInFlightPerClient(maxNumFramesInFlight),
86 mNumClients(0) {
87 if (!camObj) {
88 LOG(ERROR) << "IEvsCamera is invalid.";
89 } else {
90 // We rely on the camera having at least two buffers available since we'll hold one and
91 // expect the camera to be able to capture a new image in the background.
92 auto status = camObj->setMaxFramesInFlight(maxNumFramesInFlight);
93 if (!status.isOk()) {
94 LOG(ERROR) << "Failed to adjust the maximum number of frames in flight: "
95 << status.getServiceSpecificError();
96 }
97 }
98 }
99
100 /*
101 * Shuts down a stream handler
102 */
~StreamHandler()103 StreamHandler::~StreamHandler() {
104 shutdown();
105 }
106
107 /*
108 * Stops an active stream and releases the camera device in use
109 */
shutdown()110 void StreamHandler::shutdown() {
111 // Make sure we're not still streaming
112 blockingStopStream();
113
114 // At this point, the receiver thread is no longer running, so we can safely drop
115 // our remote object references so they can be freed
116 mEvsCamera = nullptr;
117 }
118
119 /*
120 * Requests EVS to start a video stream
121 */
startStream()122 bool StreamHandler::startStream() {
123 std::lock_guard<std::mutex> lock(mLock);
124 if (!mRunning) {
125 auto status = mEvsCamera->startVideoStream(ref<StreamHandler>());
126 if (!status.isOk()) {
127 LOG(ERROR) << "StreamHandler failed to start a video stream: "
128 << status.getServiceSpecificError();
129 return false;
130 }
131
132 // This is the first client of this stream.
133 mNumClients = 1;
134
135 // Marks ourselves as running
136 mRunning = true;
137 } else {
138 // Increase a number of active clients and the max. number of frames in
139 // flight.
140 int desired = (++mNumClients) * mMaxNumFramesInFlightPerClient;
141 auto status = mEvsCamera->setMaxFramesInFlight(desired);
142 if (!status.isOk()) {
143 LOG(ERROR) << "Failed to adjust the maximum number of frames in flight for "
144 << mNumClients << " clients. Error: " << status.getServiceSpecificError();
145 // Decrease a number of clients back.
146 mNumClients -= 1;
147 return false;
148 }
149 }
150
151 return true;
152 }
153
154 /*
155 * Requests to stop a video stream and waits for a confirmation
156 */
blockingStopStream()157 void StreamHandler::blockingStopStream() {
158 {
159 std::lock_guard lock(mLock);
160 if (!mRunning) {
161 // Nothing to do.
162 return;
163 }
164
165 if (mNumClients > 1) {
166 // Decrease a number of active clients and return.
167 --mNumClients;
168 return;
169
170 }
171
172 // Return all buffers currently held by us.
173 auto it = mReceivedBuffers.begin();
174 while (it != mReceivedBuffers.end()) {
175 // Packages a returned buffer and sends it back to the camera
176 std::vector<BufferDesc> frames(1);
177 frames[0] = std::move(*it);
178 auto status = mEvsCamera->doneWithFrame(frames);
179 if (!status.isOk()) {
180 LOG(WARNING) << "Failed to return a frame to EVS service; "
181 << "this may leak the memory: " << status.getServiceSpecificError();
182 }
183
184 it = mReceivedBuffers.erase(it);
185 }
186 }
187
188 auto status = mEvsCamera->stopVideoStream();
189 if (!status.isOk()) {
190 LOG(WARNING) << "stopVideoStream() failed but ignored.";
191 }
192
193 // Now, we are waiting for the ack from EvsManager service.
194 {
195 std::unique_lock<std::mutex> lock(mLock);
196 ScopedLockAssertion lock_assertion(mLock);
197 while (mRunning) {
198 if (!mCondition.wait_for(lock, 1s, [this]() REQUIRES(mLock) { return !mRunning; })) {
199 LOG(WARNING) << "STREAM_STOPPED event timer expired. EVS service may die.";
200 break;
201 }
202 }
203
204 // Decrease a number of active clients.
205 --mNumClients;
206 }
207 }
208
isRunning()209 bool StreamHandler::isRunning() {
210 std::lock_guard<std::mutex> lock(mLock);
211 return mRunning;
212 }
213
doneWithFrame(int bufferId)214 void StreamHandler::doneWithFrame(int bufferId) {
215 BufferDesc bufferToReturn;
216 {
217 std::lock_guard<std::mutex> lock(mLock);
218 auto it = std::find_if(mReceivedBuffers.begin(), mReceivedBuffers.end(),
219 [bufferId](BufferDesc& b) { return b.bufferId == bufferId; });
220 if (it == mReceivedBuffers.end()) {
221 LOG(DEBUG) << "Ignores a request to return unknown buffer";
222 return;
223 }
224
225 bufferToReturn = std::move(*it);
226 mReceivedBuffers.erase(it);
227 }
228
229 // Packages a returned buffer and sends it back to the camera
230 std::vector<BufferDesc> frames(1);
231 frames[0] = std::move(bufferToReturn);
232 if (auto status = mEvsCamera->doneWithFrame(frames); !status.isOk()) {
233 LOG(ERROR) << "Status = " << status.getStatus();
234 LOG(ERROR) << "Failed to return a frame (id = " << bufferId
235 << " to EVS service; this may leak the memory: "
236 << status.getServiceSpecificError();
237 }
238 }
239
doneWithFrame(const BufferDesc & buffer)240 void StreamHandler::doneWithFrame(const BufferDesc& buffer) {
241 return doneWithFrame(buffer.bufferId);
242 }
243
deliverFrame(const std::vector<BufferDesc> & buffers)244 ::ndk::ScopedAStatus StreamHandler::deliverFrame(const std::vector<BufferDesc>& buffers) {
245 LOG(DEBUG) << "Received frames from the camera, bufferId = " << buffers[0].bufferId;
246
247 const BufferDesc& bufferToUse = buffers[0];
248 size_t numBuffersInUse;
249 {
250 std::lock_guard<std::mutex> lock(mLock);
251 numBuffersInUse = mReceivedBuffers.size();
252 }
253
254 if (numBuffersInUse >= mMaxNumFramesInFlightPerClient) {
255 // We're holding more than what allowed; returns this buffer
256 // immediately.
257 doneWithFrame(bufferToUse);
258 return ::ndk::ScopedAStatus::ok();
259 }
260
261 {
262 std::lock_guard<std::mutex> lock(mLock);
263 // Records a new frameDesc and forwards to clients
264 mReceivedBuffers.push_back(dupBufferDesc(bufferToUse, /* dup= */ true));
265 LOG(DEBUG) << "Got buffer " << bufferToUse.bufferId
266 << ", total = " << mReceivedBuffers.size();
267
268 // Notify anybody who cares that things have changed
269 mCondition.notify_all();
270 }
271
272 // Forwards a new frame
273 if (!mCallback->onNewFrame(bufferToUse)) {
274 doneWithFrame(bufferToUse);
275 return ::ndk::ScopedAStatus::fromServiceSpecificError(
276 static_cast<int32_t>(EvsResult::INVALID_ARG));
277 }
278
279 return ::ndk::ScopedAStatus::ok();
280 }
281
notify(const EvsEventDesc & event)282 ::ndk::ScopedAStatus StreamHandler::notify(const EvsEventDesc& event) {
283 switch (event.aType) {
284 case EvsEventType::STREAM_STOPPED: {
285 {
286 std::lock_guard<std::mutex> lock(mLock);
287 // Signal that the last frame has been received and the stream is stopped
288 mRunning = false;
289 }
290 LOG(DEBUG) << "Received a STREAM_STOPPED event";
291 break;
292 }
293 case EvsEventType::PARAMETER_CHANGED:
294 LOG(DEBUG) << "Camera parameter 0x" << std::hex << event.payload[0] << " is set to 0x"
295 << std::hex << event.payload[1];
296 break;
297 // Below events are ignored in reference implementation.
298 case EvsEventType::STREAM_STARTED:
299 [[fallthrough]];
300 case EvsEventType::FRAME_DROPPED:
301 [[fallthrough]];
302 case EvsEventType::TIMEOUT:
303 LOG(INFO) << "Event 0x" << std::hex << static_cast<int32_t>(event.aType)
304 << " from " << (event.deviceId.empty() ? "Unknown" : event.deviceId)
305 << " is received but ignored";
306 break;
307 default:
308 LOG(ERROR) << "Unknown event id 0x" << std::hex << static_cast<int32_t>(event.aType);
309 break;
310 }
311
312 mCallback->onNewEvent(event);
313 return ::ndk::ScopedAStatus::ok();
314 }
315
316 } // namespace android::automotive::evs
317