1 /*
2 * Copyright (C) 2019 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 "VirtualCamera.h"
18
19 #include "Enumerator.h"
20 #include "HalCamera.h"
21
22 #include <android-base/file.h>
23 #include <android-base/logging.h>
24 #include <android-base/stringprintf.h>
25 #include <android/hardware_buffer.h>
26
27 #include <assert.h>
28
29 using ::android::base::StringAppendF;
30 using ::android::base::StringPrintf;
31 using ::android::base::WriteStringToFd;
32 using ::android::hardware::hidl_handle;
33 using ::android::hardware::hidl_string;
34 using ::android::hardware::hidl_vec;
35 using ::android::hardware::Return;
36 using ::android::hardware::Void;
37 using ::android::hardware::automotive::evs::V1_0::DisplayState;
38 using ::android::hardware::automotive::evs::V1_0::EvsResult;
39 using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
40 using ::android::hardware::automotive::evs::V1_1::EvsEventDesc;
41 using ::android::hardware::automotive::evs::V1_1::EvsEventType;
42
43 using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
44 using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
45 using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
46 using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
47 using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
48 using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
49 using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
50 using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
51
52 namespace android::automotive::evs::V1_1::implementation {
53
VirtualCamera(const std::vector<sp<HalCamera>> & halCameras)54 VirtualCamera::VirtualCamera(const std::vector<sp<HalCamera>>& halCameras) : mStreamState(STOPPED) {
55 for (auto&& cam : halCameras) {
56 mHalCamera.try_emplace(cam->getId(), cam);
57 }
58 }
59
~VirtualCamera()60 VirtualCamera::~VirtualCamera() {
61 shutdown();
62 }
63
shutdown()64 void VirtualCamera::shutdown() {
65 // In normal operation, the stream should already be stopped by the time we get here
66 if (mStreamState == RUNNING) {
67 // Note that if we hit this case, no terminating frame will be sent to the client,
68 // but they're probably already dead anyway.
69 LOG(WARNING) << "Virtual camera being shutdown while stream is running";
70
71 // Tell the frame delivery pipeline we don't want any more frames
72 {
73 std::unique_lock<std::mutex> lock(mFrameDeliveryMutex);
74 mStreamState = STOPPING;
75 }
76
77 // Awakes the capture thread; this thread will terminate.
78 mFramesReadySignal.notify_all();
79
80 // Join a capture thread
81 if (mCaptureThread.joinable()) {
82 mCaptureThread.join();
83 }
84
85 std::lock_guard<std::recursive_mutex> lock(mFramesHeldMutex);
86
87 // Returns buffers held by this client
88 for (auto&& [key, hwCamera] : mHalCamera) {
89 auto pHwCamera = hwCamera.promote();
90 if (pHwCamera == nullptr) {
91 LOG(WARNING) << "Camera device " << key << " is not alive.";
92 continue;
93 }
94
95 if (mFramesHeld[key].size() > 0) {
96 LOG(WARNING) << "VirtualCamera destructing with frames in flight.";
97
98 // Return to the underlying hardware camera any buffers the client was holding
99 for (auto&& heldBuffer : mFramesHeld[key]) {
100 // Tell our parent that we're done with this buffer
101 pHwCamera->doneWithFrame(heldBuffer);
102 }
103 mFramesHeld[key].clear();
104 }
105
106 // Retire from a primary client
107 pHwCamera->unsetMaster(this);
108
109 // Give the underlying hardware camera the heads up that it might be time to stop
110 pHwCamera->clientStreamEnding(this);
111
112 // Retire from the participating HW camera's client list
113 pHwCamera->disownVirtualCamera(this);
114 }
115
116 mFramesHeld.clear();
117
118 // Drop our reference to our associated hardware camera
119 mHalCamera.clear();
120 }
121 }
122
getHalCameras()123 std::vector<sp<HalCamera>> VirtualCamera::getHalCameras() {
124 std::vector<sp<HalCamera>> cameras;
125 for (auto&& [key, cam] : mHalCamera) {
126 auto ptr = cam.promote();
127 if (ptr != nullptr) {
128 cameras.emplace_back(ptr);
129 }
130 }
131
132 return cameras;
133 }
134
deliverFrame(const BufferDesc_1_1 & bufDesc)135 bool VirtualCamera::deliverFrame(const BufferDesc_1_1& bufDesc) {
136 if (mStreamState == STOPPED) {
137 // A stopped stream gets no frames
138 LOG(ERROR) << "A stopped stream should not get any frames";
139 return false;
140 }
141
142 bool dropFrame;
143 int framesHeld;
144 // Part of dropframe logic here to limit the scope of the mutex lock
145 {
146 std::lock_guard<std::recursive_mutex> lock(mFramesHeldMutex);
147 framesHeld = mFramesHeld[bufDesc.deviceId].size();
148 dropFrame = framesHeld >= mFramesAllowed;
149 if (!dropFrame) {
150 // Keep a record of this frame so we can clean up if we have to in case of client death
151 mFramesHeld[bufDesc.deviceId].emplace_back(bufDesc);
152 }
153 }
154 if (dropFrame) {
155 // Indicate that we declined to send the frame to the client because they're at quota
156 LOG(INFO) << "Skipping new frame as we hold " << framesHeld << " of " << mFramesAllowed;
157
158 if (mStream_1_1 != nullptr) {
159 // Report a frame drop to v1.1 client.
160 EvsEventDesc event;
161 event.deviceId = bufDesc.deviceId;
162 event.aType = EvsEventType::FRAME_DROPPED;
163 auto result = mStream_1_1->notify(event);
164 if (!result.isOk()) {
165 LOG(ERROR) << "Error delivering end of stream event";
166 }
167 }
168
169 // Marks that a new frame has arrived though it was not accepted
170 {
171 std::lock_guard<std::mutex> lock(mFrameDeliveryMutex);
172 mSourceCameras.erase(bufDesc.deviceId);
173 mFramesReadySignal.notify_all();
174 }
175
176 return false;
177 } else {
178 // v1.0 client uses an old frame-delivery mechanism.
179 if (mStream_1_1 == nullptr) {
180 // Forward a frame to v1.0 client
181 BufferDesc_1_0 frame_1_0 = {};
182 const AHardwareBuffer_Desc* pDesc =
183 reinterpret_cast<const AHardwareBuffer_Desc*>(&bufDesc.buffer.description);
184 frame_1_0.width = pDesc->width;
185 frame_1_0.height = pDesc->height;
186 frame_1_0.format = pDesc->format;
187 frame_1_0.usage = pDesc->usage;
188 frame_1_0.stride = pDesc->stride;
189 frame_1_0.memHandle = bufDesc.buffer.nativeHandle;
190 frame_1_0.pixelSize = bufDesc.pixelSize;
191 frame_1_0.bufferId = bufDesc.bufferId;
192
193 mStream->deliverFrame(frame_1_0);
194 } else if (mCaptureThread.joinable()) {
195 // Keep forwarding frames as long as a capture thread is alive
196 // Notify a new frame receipt
197 {
198 std::lock_guard<std::mutex> lock(mFrameDeliveryMutex);
199 mSourceCameras.erase(bufDesc.deviceId);
200 }
201 mFramesReadySignal.notify_all();
202 }
203
204 return true;
205 }
206 }
207
notify(const EvsEventDesc & event)208 bool VirtualCamera::notify(const EvsEventDesc& event) {
209 switch (event.aType) {
210 case EvsEventType::STREAM_STOPPED:
211 if (mStreamState != STOPPING) {
212 // Warn if we got an unexpected stream termination
213 LOG(WARNING) << "Stream unexpectedly stopped, current status " << mStreamState;
214
215 // Clean up the resource and forward an event to the client
216 stopVideoStream();
217
218 // This event is handled properly.
219 return true;
220 }
221
222 if (mStream_1_1 == nullptr) {
223 // Send a null frame instead, for v1.0 client
224 auto result = mStream->deliverFrame({});
225 if (!result.isOk()) {
226 LOG(ERROR) << "Error delivering end of stream marker";
227 }
228 }
229 break;
230
231 // v1.0 client will ignore all other events.
232 case EvsEventType::PARAMETER_CHANGED:
233 LOG(DEBUG) << "A camera parameter " << event.payload[0] << " is set to "
234 << event.payload[1];
235 break;
236
237 case EvsEventType::MASTER_RELEASED:
238 LOG(DEBUG) << "The primary client has been released";
239 break;
240
241 default:
242 LOG(WARNING) << "Unknown event id " << static_cast<int32_t>(event.aType);
243 break;
244 }
245
246 if (mStream_1_1 != nullptr) {
247 // Forward a received event to the v1.1 client
248 auto result = mStream_1_1->notify(event);
249 if (!result.isOk()) {
250 LOG(ERROR) << "Failed to forward an event";
251 return false;
252 }
253 }
254
255 return true;
256 }
257
258 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
getCameraInfo(getCameraInfo_cb info_cb)259 Return<void> VirtualCamera::getCameraInfo(getCameraInfo_cb info_cb) {
260 // Straight pass through to hardware layer
261 if (mHalCamera.size() > 1) {
262 LOG(ERROR) << __FUNCTION__ << " must NOT be called on a logical camera object.";
263 info_cb({});
264 return Void();
265 }
266
267 auto halCamera = mHalCamera.begin()->second.promote();
268 if (halCamera != nullptr) {
269 return halCamera->getHwCamera()->getCameraInfo(info_cb);
270 } else {
271 info_cb({});
272 return Void();
273 }
274 }
275
setMaxFramesInFlight(uint32_t bufferCount)276 Return<EvsResult> VirtualCamera::setMaxFramesInFlight(uint32_t bufferCount) {
277 // How many buffers are we trying to add (or remove if negative)
278 int bufferCountChange = bufferCount - mFramesAllowed;
279
280 // Ask our parent for more buffers
281 bool result = true;
282 std::vector<sp<HalCamera>> changedCameras;
283 for (auto&& [key, hwCamera] : mHalCamera) {
284 auto pHwCam = hwCamera.promote();
285 if (pHwCam == nullptr) {
286 continue;
287 }
288
289 result = pHwCam->changeFramesInFlight(bufferCountChange);
290 if (!result) {
291 LOG(ERROR) << key << ": Failed to change buffer count by " << bufferCountChange
292 << " to " << bufferCount;
293 break;
294 }
295
296 changedCameras.emplace_back(pHwCam);
297 }
298
299 // Update our notion of how many frames we're allowed
300 mFramesAllowed = bufferCount;
301
302 if (!result) {
303 // Rollback changes because we failed to update all cameras
304 for (auto&& hwCamera : changedCameras) {
305 LOG(WARNING) << "Rollback a change on " << hwCamera->getId();
306 hwCamera->changeFramesInFlight(-bufferCountChange);
307 }
308
309 // Restore the original buffer count
310 mFramesAllowed -= bufferCountChange;
311 return EvsResult::BUFFER_NOT_AVAILABLE;
312 } else {
313 return EvsResult::OK;
314 }
315 }
316
startVideoStream(const::android::sp<IEvsCameraStream_1_0> & stream)317 Return<EvsResult> VirtualCamera::startVideoStream(
318 const ::android::sp<IEvsCameraStream_1_0>& stream) {
319 // We only support a single stream at a time
320 if (mStreamState != STOPPED) {
321 LOG(ERROR) << "Ignoring startVideoStream call when a stream is already running.";
322 return EvsResult::STREAM_ALREADY_RUNNING;
323 }
324
325 // Validate our held frame count is starting out at zero as we expect
326 {
327 std::lock_guard<std::recursive_mutex> lock(mFramesHeldMutex);
328 assert(mFramesHeld.size() == 0);
329 }
330
331 // Record the user's callback for use when we have a frame ready
332 mStream = stream;
333 mStream_1_1 = IEvsCameraStream_1_1::castFrom(stream).withDefault(nullptr);
334 if (mStream_1_1 == nullptr) {
335 LOG(INFO) << "Start video stream for v1.0 client.";
336 } else {
337 LOG(INFO) << "Start video stream for v1.1 client.";
338 }
339
340 mStreamState = RUNNING;
341
342 // Tell the underlying camera hardware that we want to stream
343 bool cleanUpAndReturn = true;
344 auto iter = mHalCamera.begin();
345 while (iter != mHalCamera.end()) {
346 auto pHwCamera = iter->second.promote();
347 if (pHwCamera == nullptr) {
348 LOG(WARNING) << "Failed to start a video stream on " << iter->first;
349 ++iter;
350 continue;
351 }
352
353 LOG(INFO) << __FUNCTION__ << " starts a video stream on " << iter->first;
354 Return<EvsResult> result = pHwCamera->clientStreamStarting();
355 if ((!result.isOk()) || (result != EvsResult::OK)) {
356 LOG(ERROR) << "Failed to start a video stream on " << iter->first;
357 cleanUpAndReturn = true;
358 break;
359 }
360
361 cleanUpAndReturn = false;
362 ++iter;
363 }
364
365 if (cleanUpAndReturn) {
366 // If we failed to start the underlying stream, then we're not actually running
367 mStream = mStream_1_1 = nullptr;
368 mStreamState = STOPPED;
369
370 // Request to stop streams started by this client.
371 auto rb = mHalCamera.begin();
372 while (rb != iter) {
373 auto ptr = rb->second.promote();
374 if (ptr != nullptr) {
375 ptr->clientStreamEnding(this);
376 }
377 ++rb;
378 }
379 return EvsResult::UNDERLYING_SERVICE_ERROR;
380 }
381
382 // Start a thread that waits on the fence and forwards collected frames
383 // to the v1.1 client.
384 auto pHwCamera = mHalCamera.begin()->second.promote();
385 if (mStream_1_1 != nullptr && pHwCamera != nullptr) {
386 mCaptureThread = std::thread([this]() {
387 // TODO(b/145466570): With a proper camera hang handler, we may want
388 // to reduce an amount of timeout.
389 constexpr auto kFrameTimeout = 5s; // timeout in seconds.
390 int64_t lastFrameTimestamp = -1;
391 while (mStreamState == RUNNING) {
392 unsigned count = 0;
393 for (auto&& [key, hwCamera] : mHalCamera) {
394 auto pHwCamera = hwCamera.promote();
395 if (pHwCamera == nullptr) {
396 LOG(WARNING) << "Invalid camera " << key << " is ignored.";
397 continue;
398 }
399
400 pHwCamera->requestNewFrame(this, lastFrameTimestamp);
401 {
402 std::lock_guard<std::mutex> lock(mFrameDeliveryMutex);
403 mSourceCameras.emplace(pHwCamera->getId());
404 }
405 ++count;
406 }
407
408 std::unique_lock<std::mutex> lock(mFrameDeliveryMutex);
409 if (!mFramesReadySignal.wait_for(lock, kFrameTimeout,
410 [this]() REQUIRES(mFrameDeliveryMutex) {
411 // Stops waiting if
412 // 1) we've requested to stop capturing
413 // new frames
414 // 2) or, we've got all frames
415 return mStreamState != RUNNING ||
416 mSourceCameras.empty();
417 })) {
418 // This happens when either a new frame does not arrive
419 // before a timer expires or we're requested to stop
420 // capturing frames.
421 break;
422 } else if (mStreamState == RUNNING) {
423 // Fetch frames and forward to the client
424 std::lock_guard<std::recursive_mutex> lock(mFramesHeldMutex);
425 if (mFramesHeld.size() > 0 && mStream_1_1 != nullptr) {
426 // Pass this buffer through to our client
427 hardware::hidl_vec<BufferDesc_1_1> frames;
428 frames.resize(count);
429 unsigned i = 0;
430 for (auto&& [key, hwCamera] : mHalCamera) {
431 auto pHwCamera = hwCamera.promote();
432 if (pHwCamera == nullptr) {
433 continue;
434 }
435 if (mFramesHeld[key].size() == 0) {
436 continue;
437 }
438
439 const auto frame = mFramesHeld[key].back();
440 if (frame.timestamp > lastFrameTimestamp) {
441 lastFrameTimestamp = frame.timestamp;
442 }
443 frames[i++] = frame;
444 }
445
446 auto ret = mStream_1_1->deliverFrame_1_1(frames);
447 if (!ret.isOk()) {
448 LOG(WARNING) << "Failed to forward frames";
449 }
450 }
451 } else if (mStreamState != RUNNING) {
452 LOG(DEBUG) << "Requested to stop capturing frames";
453 }
454 }
455
456 LOG(DEBUG) << "Exiting a capture thread";
457 });
458 }
459
460 // TODO(changyeon):
461 // Detect and exit if we encounter a stalled stream or unresponsive driver?
462 // Consider using a timer and watching for frame arrival?
463
464 return EvsResult::OK;
465 }
466
doneWithFrame(const BufferDesc_1_0 & buffer)467 Return<void> VirtualCamera::doneWithFrame(const BufferDesc_1_0& buffer) {
468 std::lock_guard<std::recursive_mutex> lock(mFramesHeldMutex);
469
470 if (buffer.memHandle == nullptr) {
471 LOG(ERROR) << "Ignoring doneWithFrame called with invalid handle";
472 } else if (mFramesHeld.size() > 1) {
473 LOG(ERROR) << __FUNCTION__ << " must NOT be called on a logical camera object.";
474 } else {
475 // Find this buffer in our "held" list
476 auto& frameQueue = mFramesHeld.begin()->second;
477 auto it = frameQueue.begin();
478 while (it != frameQueue.end()) {
479 if (it->bufferId == buffer.bufferId) {
480 // found it!
481 break;
482 }
483 ++it;
484 }
485 if (it == frameQueue.end()) {
486 // We should always find the frame in our "held" list
487 LOG(ERROR) << "Ignoring doneWithFrame called with unrecognized frameID "
488 << buffer.bufferId;
489 } else {
490 // Take this frame out of our "held" list
491 frameQueue.erase(it);
492
493 // Tell our parent that we're done with this buffer
494 auto pHwCamera = mHalCamera.begin()->second.promote();
495 if (pHwCamera != nullptr) {
496 pHwCamera->doneWithFrame(buffer);
497 } else {
498 LOG(WARNING) << "Possible memory leak because a device "
499 << mHalCamera.begin()->first << " is not valid.";
500 }
501 }
502 }
503
504 return Void();
505 }
506
stopVideoStream()507 Return<void> VirtualCamera::stopVideoStream() {
508 if (mStreamState == RUNNING) {
509 // Tell the frame delivery pipeline we don't want any more frames
510 mStreamState = STOPPING;
511
512 // Awake the capture thread; this thread will terminate.
513 mFramesReadySignal.notify_all();
514
515 // Deliver the stream-ending notification
516 if (mStream_1_1 != nullptr) {
517 // v1.1 client waits for a stream stopped event
518 EvsEventDesc event;
519 event.aType = EvsEventType::STREAM_STOPPED;
520 auto result = mStream_1_1->notify(event);
521 if (!result.isOk()) {
522 LOG(ERROR) << "Error delivering end of stream event";
523 }
524 } else {
525 // v1.0 client expects a null frame at the end of the stream
526 auto result = mStream->deliverFrame({});
527 if (!result.isOk()) {
528 LOG(ERROR) << "Error delivering end of stream marker";
529 }
530 }
531
532 // Since we are single threaded, no frame can be delivered while this function is running,
533 // so we can go directly to the STOPPED state here on the server.
534 // Note, however, that there still might be frames already queued that client will see
535 // after returning from the client side of this call.
536 mStreamState = STOPPED;
537
538 // Give the underlying hardware camera the heads up that it might be time to stop
539 for (auto&& [key, hwCamera] : mHalCamera) {
540 auto pHwCamera = hwCamera.promote();
541 if (pHwCamera != nullptr) {
542 pHwCamera->clientStreamEnding(this);
543 }
544 }
545
546 // Signal a condition to unblock a capture thread and then join
547 {
548 std::lock_guard<std::mutex> lock(mFrameDeliveryMutex);
549 mSourceCameras.clear();
550 mFramesReadySignal.notify_all();
551 }
552
553 if (mCaptureThread.joinable()) {
554 mCaptureThread.join();
555 }
556 }
557
558 return Void();
559 }
560
getExtendedInfo(uint32_t opaqueIdentifier)561 Return<int32_t> VirtualCamera::getExtendedInfo(uint32_t opaqueIdentifier) {
562 if (mHalCamera.size() > 1) {
563 LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
564 return 0;
565 }
566
567 // Pass straight through to the hardware device
568 auto pHwCamera = mHalCamera.begin()->second.promote();
569 if (pHwCamera != nullptr) {
570 return pHwCamera->getHwCamera()->getExtendedInfo(opaqueIdentifier);
571 } else {
572 LOG(WARNING) << mHalCamera.begin()->first << " is invalid.";
573 return 0;
574 }
575 }
576
setExtendedInfo(uint32_t opaqueIdentifier,int32_t opaqueValue)577 Return<EvsResult> VirtualCamera::setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) {
578 if (mHalCamera.size() > 1) {
579 LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
580 return EvsResult::INVALID_ARG;
581 }
582
583 // Pass straight through to the hardware device
584 auto pHwCamera = mHalCamera.begin()->second.promote();
585 if (pHwCamera != nullptr) {
586 return pHwCamera->getHwCamera()->setExtendedInfo(opaqueIdentifier, opaqueValue);
587 } else {
588 LOG(WARNING) << mHalCamera.begin()->first << " is invalid.";
589 return EvsResult::INVALID_ARG;
590 }
591 }
592
593 // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
getCameraInfo_1_1(getCameraInfo_1_1_cb info_cb)594 Return<void> VirtualCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb info_cb) {
595 if (mHalCamera.size() > 1) {
596 // Logical camera description is stored in VirtualCamera object.
597 info_cb(*mDesc);
598 return Void();
599 }
600
601 // Straight pass through to hardware layer
602 auto pHwCamera = mHalCamera.begin()->second.promote();
603 if (pHwCamera == nullptr) {
604 // Return an empty list
605 info_cb({});
606 return Void();
607 }
608
609 auto hwCamera_1_1 = IEvsCamera_1_1::castFrom(pHwCamera->getHwCamera()).withDefault(nullptr);
610 if (hwCamera_1_1 != nullptr) {
611 return hwCamera_1_1->getCameraInfo_1_1(info_cb);
612 } else {
613 // Return an empty list
614 info_cb({});
615 return Void();
616 }
617 }
618
getPhysicalCameraInfo(const hidl_string & deviceId,getPhysicalCameraInfo_cb info_cb)619 Return<void> VirtualCamera::getPhysicalCameraInfo(const hidl_string& deviceId,
620 getPhysicalCameraInfo_cb info_cb) {
621 auto device = mHalCamera.find(deviceId);
622 if (device != mHalCamera.end()) {
623 // Straight pass through to hardware layer
624 auto pHwCamera = device->second.promote();
625 if (pHwCamera != nullptr) {
626 auto hwCamera_1_1 =
627 IEvsCamera_1_1::castFrom(pHwCamera->getHwCamera()).withDefault(nullptr);
628 if (hwCamera_1_1 != nullptr) {
629 return hwCamera_1_1->getCameraInfo_1_1(info_cb);
630 } else {
631 LOG(WARNING) << "Failed to promote HW camera to v1.1.";
632 }
633 } else {
634 LOG(WARNING) << "Camera device " << deviceId << " is not alive.";
635 }
636 } else {
637 LOG(WARNING) << " Requested device " << deviceId << " does not back this device.";
638 }
639
640 // Return an empty list
641 info_cb({});
642 return Void();
643 }
644
doneWithFrame_1_1(const hardware::hidl_vec<BufferDesc_1_1> & buffers)645 Return<EvsResult> VirtualCamera::doneWithFrame_1_1(
646 const hardware::hidl_vec<BufferDesc_1_1>& buffers) {
647 std::lock_guard<std::recursive_mutex> lock(mFramesHeldMutex);
648 for (auto&& buffer : buffers) {
649 if (buffer.buffer.nativeHandle == nullptr) {
650 LOG(WARNING) << "Ignoring doneWithFrame called with invalid handle";
651 } else {
652 // Find this buffer in our "held" list
653 auto it = mFramesHeld[buffer.deviceId].begin();
654 while (it != mFramesHeld[buffer.deviceId].end()) {
655 if (it->bufferId == buffer.bufferId) {
656 // found it!
657 break;
658 }
659 ++it;
660 }
661 if (it == mFramesHeld[buffer.deviceId].end()) {
662 // We should always find the frame in our "held" list
663 LOG(ERROR) << "Ignoring doneWithFrame called with unrecognized frameID "
664 << buffer.bufferId;
665 } else {
666 // Take this frame out of our "held" list
667 mFramesHeld[buffer.deviceId].erase(it);
668
669 // Tell our parent that we're done with this buffer
670 auto pHwCamera = mHalCamera[buffer.deviceId].promote();
671 if (pHwCamera != nullptr) {
672 pHwCamera->doneWithFrame(buffer);
673 } else {
674 LOG(WARNING) << "Possible memory leak; " << buffer.deviceId << " is not valid.";
675 }
676 }
677 }
678 }
679
680 return EvsResult::OK;
681 }
682
setMaster()683 Return<EvsResult> VirtualCamera::setMaster() {
684 if (mHalCamera.size() > 1) {
685 LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
686 return EvsResult::INVALID_ARG;
687 }
688
689 auto pHwCamera = mHalCamera.begin()->second.promote();
690 if (pHwCamera != nullptr) {
691 return pHwCamera->setMaster(this);
692 } else {
693 LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
694 return EvsResult::INVALID_ARG;
695 }
696 }
697
forceMaster(const sp<IEvsDisplay_1_0> & display)698 Return<EvsResult> VirtualCamera::forceMaster(const sp<IEvsDisplay_1_0>& display) {
699 if (mHalCamera.size() > 1) {
700 LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
701 return EvsResult::INVALID_ARG;
702 }
703
704 if (display == nullptr) {
705 LOG(ERROR) << __FUNCTION__ << ": Passed display is invalid";
706 return EvsResult::INVALID_ARG;
707 }
708
709 DisplayState state = display->getDisplayState();
710 if (state == DisplayState::NOT_OPEN || state == DisplayState::DEAD ||
711 state >= DisplayState::NUM_STATES) {
712 LOG(ERROR) << __FUNCTION__ << ": Passed display is in invalid state";
713 return EvsResult::INVALID_ARG;
714 }
715
716 auto pHwCamera = mHalCamera.begin()->second.promote();
717 if (pHwCamera != nullptr) {
718 return pHwCamera->forceMaster(this);
719 } else {
720 LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
721 return EvsResult::INVALID_ARG;
722 }
723 }
724
unsetMaster()725 Return<EvsResult> VirtualCamera::unsetMaster() {
726 if (mHalCamera.size() > 1) {
727 LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
728 return EvsResult::INVALID_ARG;
729 }
730
731 auto pHwCamera = mHalCamera.begin()->second.promote();
732 if (pHwCamera != nullptr) {
733 return pHwCamera->unsetMaster(this);
734 } else {
735 LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
736 return EvsResult::INVALID_ARG;
737 }
738 }
739
getParameterList(getParameterList_cb _hidl_cb)740 Return<void> VirtualCamera::getParameterList(getParameterList_cb _hidl_cb) {
741 if (mHalCamera.size() > 1) {
742 LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
743
744 // Return an empty list
745 _hidl_cb({});
746 return Void();
747 }
748
749 // Straight pass through to hardware layer
750 auto pHwCamera = mHalCamera.begin()->second.promote();
751 if (pHwCamera == nullptr) {
752 LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
753
754 // Return an empty list
755 _hidl_cb({});
756 return Void();
757 }
758
759 auto hwCamera_1_1 = IEvsCamera_1_1::castFrom(pHwCamera->getHwCamera()).withDefault(nullptr);
760 if (hwCamera_1_1 != nullptr) {
761 return hwCamera_1_1->getParameterList(_hidl_cb);
762 } else {
763 LOG(WARNING) << "Camera device " << mHalCamera.begin()->first
764 << " does not support a parameter programming.";
765
766 // Return an empty list
767 _hidl_cb({});
768 return Void();
769 }
770 }
771
getIntParameterRange(CameraParam id,getIntParameterRange_cb _hidl_cb)772 Return<void> VirtualCamera::getIntParameterRange(CameraParam id, getIntParameterRange_cb _hidl_cb) {
773 if (mHalCamera.size() > 1) {
774 LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
775
776 // Return [0, 0, 0]
777 _hidl_cb(0, 0, 0);
778 return Void();
779 }
780
781 // Straight pass through to hardware layer
782 auto pHwCamera = mHalCamera.begin()->second.promote();
783 if (pHwCamera == nullptr) {
784 LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
785
786 // Return [0, 0, 0]
787 _hidl_cb(0, 0, 0);
788 return Void();
789 }
790
791 auto hwCamera_1_1 = IEvsCamera_1_1::castFrom(pHwCamera->getHwCamera()).withDefault(nullptr);
792 if (hwCamera_1_1 != nullptr) {
793 return hwCamera_1_1->getIntParameterRange(id, _hidl_cb);
794 } else {
795 LOG(WARNING) << "Camera device " << mHalCamera.begin()->first
796 << " does not support a parameter programming.";
797
798 // Return [0, 0, 0]
799 _hidl_cb(0, 0, 0);
800 return Void();
801 }
802 return Void();
803 }
804
setIntParameter(CameraParam id,int32_t value,setIntParameter_cb _hidl_cb)805 Return<void> VirtualCamera::setIntParameter(CameraParam id, int32_t value,
806 setIntParameter_cb _hidl_cb) {
807 hardware::hidl_vec<int32_t> values;
808 EvsResult status = EvsResult::INVALID_ARG;
809 if (mHalCamera.size() > 1) {
810 LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
811 _hidl_cb(status, values);
812 return Void();
813 }
814
815 auto pHwCamera = mHalCamera.begin()->second.promote();
816 if (pHwCamera == nullptr) {
817 LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
818 _hidl_cb(status, values);
819 return Void();
820 }
821
822 status = pHwCamera->setParameter(this, id, &value);
823
824 values.resize(1);
825 values[0] = value;
826 _hidl_cb(status, values);
827
828 return Void();
829 }
830
getIntParameter(CameraParam id,getIntParameter_cb _hidl_cb)831 Return<void> VirtualCamera::getIntParameter(CameraParam id, getIntParameter_cb _hidl_cb) {
832 hardware::hidl_vec<int32_t> values;
833 EvsResult status = EvsResult::INVALID_ARG;
834 if (mHalCamera.size() > 1) {
835 LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
836 _hidl_cb(status, values);
837 return Void();
838 }
839
840 auto pHwCamera = mHalCamera.begin()->second.promote();
841 if (pHwCamera == nullptr) {
842 LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
843 _hidl_cb(status, values);
844 return Void();
845 }
846
847 int32_t value;
848 status = pHwCamera->getParameter(id, &value);
849
850 values.resize(1);
851 values[0] = value;
852 _hidl_cb(status, values);
853
854 return Void();
855 }
856
setExtendedInfo_1_1(uint32_t opaqueIdentifier,const hidl_vec<uint8_t> & opaqueValue)857 Return<EvsResult> VirtualCamera::setExtendedInfo_1_1(uint32_t opaqueIdentifier,
858 const hidl_vec<uint8_t>& opaqueValue) {
859 hardware::hidl_vec<int32_t> values;
860 if (mHalCamera.size() > 1) {
861 LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
862 return EvsResult::INVALID_ARG;
863 }
864
865 auto pHwCamera = mHalCamera.begin()->second.promote();
866 if (pHwCamera == nullptr) {
867 LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
868 return EvsResult::INVALID_ARG;
869 } else {
870 auto hwCamera = IEvsCamera_1_1::castFrom(pHwCamera->getHwCamera()).withDefault(nullptr);
871 if (hwCamera != nullptr) {
872 return hwCamera->setExtendedInfo_1_1(opaqueIdentifier, opaqueValue);
873 } else {
874 LOG(ERROR) << "Underlying hardware camera does not implement v1.1 interfaces.";
875 return EvsResult::INVALID_ARG;
876 }
877 }
878 }
879
getExtendedInfo_1_1(uint32_t opaqueIdentifier,getExtendedInfo_1_1_cb _hidl_cb)880 Return<void> VirtualCamera::getExtendedInfo_1_1(uint32_t opaqueIdentifier,
881 getExtendedInfo_1_1_cb _hidl_cb) {
882 hardware::hidl_vec<uint8_t> values;
883 EvsResult status = EvsResult::INVALID_ARG;
884 if (mHalCamera.size() > 1) {
885 LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
886 _hidl_cb(status, values);
887 return Void();
888 }
889
890 auto pHwCamera = mHalCamera.begin()->second.promote();
891 if (pHwCamera == nullptr) {
892 LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
893 _hidl_cb(status, values);
894 } else {
895 auto hwCamera = IEvsCamera_1_1::castFrom(pHwCamera->getHwCamera()).withDefault(nullptr);
896 if (hwCamera != nullptr) {
897 hwCamera->getExtendedInfo_1_1(opaqueIdentifier, _hidl_cb);
898 } else {
899 LOG(ERROR) << "Underlying hardware camera does not implement v1.1 interfaces.";
900 _hidl_cb(status, values);
901 }
902 }
903
904 return Void();
905 }
906
importExternalBuffers(const hidl_vec<BufferDesc_1_1> & buffers,importExternalBuffers_cb _hidl_cb)907 Return<void> VirtualCamera::importExternalBuffers(const hidl_vec<BufferDesc_1_1>& buffers,
908 importExternalBuffers_cb _hidl_cb) {
909 if (mHalCamera.size() > 1) {
910 LOG(WARNING) << "Logical camera device does not support " << __FUNCTION__;
911 _hidl_cb(EvsResult::UNDERLYING_SERVICE_ERROR, 0);
912 return {};
913 }
914
915 auto pHwCamera = mHalCamera.begin()->second.promote();
916 if (pHwCamera == nullptr) {
917 LOG(WARNING) << "Camera device " << mHalCamera.begin()->first << " is not alive.";
918 _hidl_cb(EvsResult::UNDERLYING_SERVICE_ERROR, 0);
919 return {};
920 }
921
922 int delta = 0;
923 if (!pHwCamera->changeFramesInFlight(buffers, &delta)) {
924 LOG(ERROR) << "Failed to add extenral capture buffers.";
925 _hidl_cb(EvsResult::UNDERLYING_SERVICE_ERROR, 0);
926 return {};
927 }
928
929 mFramesAllowed += delta;
930 _hidl_cb(EvsResult::OK, delta);
931 return {};
932 }
933
toString(const char * indent) const934 std::string VirtualCamera::toString(const char* indent) const {
935 std::string buffer;
936 StringAppendF(&buffer,
937 "%sLogical camera device: %s\n"
938 "%sFramesAllowed: %u\n"
939 "%sFrames in use:\n",
940 indent, mHalCamera.size() > 1 ? "T" : "F", indent, mFramesAllowed, indent);
941
942 std::string next_indent(indent);
943 next_indent += "\t";
944 std::lock_guard<std::recursive_mutex> lock(mFramesHeldMutex);
945 for (auto&& [id, queue] : mFramesHeld) {
946 StringAppendF(&buffer, "%s%s: %d\n", next_indent.c_str(), id.c_str(),
947 static_cast<int>(queue.size()));
948 }
949 StringAppendF(&buffer, "%sCurrent stream state: %d\n", indent, mStreamState);
950
951 return buffer;
952 }
953
954 } // namespace android::automotive::evs::V1_1::implementation
955