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 "Enumerator.h"
18 #include "HalCamera.h"
19 #include "VirtualCamera.h"
20
21 #include <android-base/file.h>
22 #include <android-base/logging.h>
23 #include <android-base/strings.h>
24
25 namespace android {
26 namespace automotive {
27 namespace evs {
28 namespace V1_1 {
29 namespace implementation {
30
31
32 // TODO(changyeon):
33 // We need to hook up death monitoring to detect stream death so we can attempt a reconnect
34
35 using ::android::base::StringAppendF;
36 using ::android::base::WriteStringToFd;
37
~HalCamera()38 HalCamera::~HalCamera() {
39 // Reports the usage statistics before the destruction
40 // EvsUsageStatsReported atom is defined in
41 // frameworks/base/cmds/statsd/src/atoms.proto
42 mUsageStats->writeStats();
43 }
44
makeVirtualCamera()45 sp<VirtualCamera> HalCamera::makeVirtualCamera() {
46
47 // Create the client camera interface object
48 std::vector<sp<HalCamera>> sourceCameras;
49 sourceCameras.reserve(1);
50 sourceCameras.emplace_back(this);
51 sp<VirtualCamera> client = new VirtualCamera(sourceCameras);
52 if (client == nullptr) {
53 LOG(ERROR) << "Failed to create client camera object";
54 return nullptr;
55 }
56
57 if (!ownVirtualCamera(client)) {
58 LOG(ERROR) << "Failed to own a client camera object";
59 client = nullptr;
60 }
61
62 return client;
63 }
64
65
ownVirtualCamera(sp<VirtualCamera> virtualCamera)66 bool HalCamera::ownVirtualCamera(sp<VirtualCamera> virtualCamera) {
67
68 if (virtualCamera == nullptr) {
69 LOG(ERROR) << "Failed to create virtualCamera camera object";
70 return false;
71 }
72
73 // Make sure we have enough buffers available for all our clients
74 if (!changeFramesInFlight(virtualCamera->getAllowedBuffers())) {
75 // Gah! We couldn't get enough buffers, so we can't support this virtualCamera
76 // Null the pointer, dropping our reference, thus destroying the virtualCamera object
77 return false;
78 }
79
80 // Add this virtualCamera to our ownership list via weak pointer
81 mClients.emplace_back(virtualCamera);
82
83 // Update statistics
84 mUsageStats->updateNumClients(mClients.size());
85
86 return true;
87 }
88
89
disownVirtualCamera(sp<VirtualCamera> virtualCamera)90 void HalCamera::disownVirtualCamera(sp<VirtualCamera> virtualCamera) {
91 // Ignore calls with null pointers
92 if (virtualCamera.get() == nullptr) {
93 LOG(WARNING) << "Ignoring disownVirtualCamera call with null pointer";
94 return;
95 }
96
97 // Remove the virtual camera from our client list
98 unsigned clientCount = mClients.size();
99 mClients.remove(virtualCamera);
100 if (clientCount != mClients.size() + 1) {
101 LOG(ERROR) << "Couldn't find camera in our client list to remove it";
102 }
103
104 // Recompute the number of buffers required with the target camera removed from the list
105 if (!changeFramesInFlight(0)) {
106 LOG(ERROR) << "Error when trying to reduce the in flight buffer count";
107 }
108
109 // Update statistics
110 mUsageStats->updateNumClients(mClients.size());
111 }
112
113
changeFramesInFlight(int delta)114 bool HalCamera::changeFramesInFlight(int delta) {
115 // Walk all our clients and count their currently required frames
116 unsigned bufferCount = 0;
117 for (auto&& client : mClients) {
118 sp<VirtualCamera> virtCam = client.promote();
119 if (virtCam != nullptr) {
120 bufferCount += virtCam->getAllowedBuffers();
121 }
122 }
123
124 // Add the requested delta
125 bufferCount += delta;
126
127 // Never drop below 1 buffer -- even if all client cameras get closed
128 if (bufferCount < 1) {
129 bufferCount = 1;
130 }
131
132 // Ask the hardware for the resulting buffer count
133 Return<EvsResult> result = mHwCamera->setMaxFramesInFlight(bufferCount);
134 bool success = (result.isOk() && result == EvsResult::OK);
135
136 // Update the size of our array of outstanding frame records
137 if (success) {
138 std::vector<FrameRecord> newRecords;
139 newRecords.reserve(bufferCount);
140
141 // Copy and compact the old records that are still active
142 for (const auto& rec : mFrames) {
143 if (rec.refCount > 0) {
144 newRecords.emplace_back(rec);
145 }
146 }
147 if (newRecords.size() > (unsigned)bufferCount) {
148 LOG(WARNING) << "We found more frames in use than requested.";
149 }
150
151 mFrames.swap(newRecords);
152 }
153
154 return success;
155 }
156
157
changeFramesInFlight(const hidl_vec<BufferDesc_1_1> & buffers,int * delta)158 bool HalCamera::changeFramesInFlight(const hidl_vec<BufferDesc_1_1>& buffers,
159 int* delta) {
160 // Return immediately if a list is empty.
161 if (buffers.size() < 1) {
162 LOG(DEBUG) << "No external buffers to add.";
163 return true;
164 }
165
166 // Walk all our clients and count their currently required frames
167 auto bufferCount = 0;
168 for (auto&& client : mClients) {
169 sp<VirtualCamera> virtCam = client.promote();
170 if (virtCam != nullptr) {
171 bufferCount += virtCam->getAllowedBuffers();
172 }
173 }
174
175 EvsResult status = EvsResult::OK;
176 // Ask the hardware for the resulting buffer count
177 mHwCamera->importExternalBuffers(buffers,
178 [&](auto result, auto added) {
179 status = result;
180 *delta = added;
181 });
182 if (status != EvsResult::OK) {
183 LOG(ERROR) << "Failed to add external capture buffers.";
184 return false;
185 }
186
187 bufferCount += *delta;
188
189 // Update the size of our array of outstanding frame records
190 std::vector<FrameRecord> newRecords;
191 newRecords.reserve(bufferCount);
192
193 // Copy and compact the old records that are still active
194 for (const auto& rec : mFrames) {
195 if (rec.refCount > 0) {
196 newRecords.emplace_back(rec);
197 }
198 }
199
200 if (newRecords.size() > (unsigned)bufferCount) {
201 LOG(WARNING) << "We found more frames in use than requested.";
202 }
203
204 mFrames.swap(newRecords);
205
206 return true;
207 }
208
209
requestNewFrame(sp<VirtualCamera> client,const int64_t lastTimestamp)210 void HalCamera::requestNewFrame(sp<VirtualCamera> client,
211 const int64_t lastTimestamp) {
212 FrameRequest req;
213 req.client = client;
214 req.timestamp = lastTimestamp;
215
216 std::lock_guard<std::mutex> lock(mFrameMutex);
217 mNextRequests->push_back(req);
218 }
219
220
clientStreamStarting()221 Return<EvsResult> HalCamera::clientStreamStarting() {
222 Return<EvsResult> result = EvsResult::OK;
223
224 if (mStreamState == STOPPED) {
225 mStreamState = RUNNING;
226 result = mHwCamera->startVideoStream(this);
227 }
228
229 return result;
230 }
231
232
clientStreamEnding(const VirtualCamera * client)233 void HalCamera::clientStreamEnding(const VirtualCamera* client) {
234 {
235 std::lock_guard<std::mutex> lock(mFrameMutex);
236 auto itReq = mNextRequests->begin();
237 while (itReq != mNextRequests->end()) {
238 if (itReq->client == client) {
239 break;
240 } else {
241 ++itReq;
242 }
243 }
244
245 if (itReq != mNextRequests->end()) {
246 mNextRequests->erase(itReq);
247 }
248
249 auto itCam = mClients.begin();
250 while (itCam != mClients.end()) {
251 if (itCam->promote() == client) {
252 break;
253 } else {
254 ++itCam;
255 }
256 }
257
258 if (itCam != mClients.end()) {
259 // Remove a client, which requested to stop, from the list.
260 mClients.erase(itCam);
261 }
262 }
263
264 // Do we still have a running client?
265 bool stillRunning = false;
266 for (auto&& client : mClients) {
267 sp<VirtualCamera> virtCam = client.promote();
268 if (virtCam != nullptr) {
269 stillRunning |= virtCam->isStreaming();
270 }
271 }
272
273 // If not, then stop the hardware stream
274 if (!stillRunning) {
275 mStreamState = STOPPING;
276 mHwCamera->stopVideoStream();
277 }
278 }
279
280
doneWithFrame(const BufferDesc_1_0 & buffer)281 Return<void> HalCamera::doneWithFrame(const BufferDesc_1_0& buffer) {
282 // Find this frame in our list of outstanding frames
283 unsigned i;
284 for (i = 0; i < mFrames.size(); i++) {
285 if (mFrames[i].frameId == buffer.bufferId) {
286 break;
287 }
288 }
289 if (i == mFrames.size()) {
290 LOG(ERROR) << "We got a frame back with an ID we don't recognize!";
291 } else {
292 // Are there still clients using this buffer?
293 mFrames[i].refCount--;
294 if (mFrames[i].refCount <= 0) {
295 // Since all our clients are done with this buffer, return it to the device layer
296 mHwCamera->doneWithFrame(buffer);
297
298 // Counts a returned buffer
299 mUsageStats->framesReturned();
300 }
301 }
302
303 return Void();
304 }
305
306
doneWithFrame(const BufferDesc_1_1 & buffer)307 Return<void> HalCamera::doneWithFrame(const BufferDesc_1_1& buffer) {
308 // Find this frame in our list of outstanding frames
309 unsigned i;
310 for (i = 0; i < mFrames.size(); i++) {
311 if (mFrames[i].frameId == buffer.bufferId) {
312 break;
313 }
314 }
315 if (i == mFrames.size()) {
316 LOG(ERROR) << "We got a frame back with an ID we don't recognize!";
317 } else {
318 // Are there still clients using this buffer?
319 mFrames[i].refCount--;
320 if (mFrames[i].refCount <= 0) {
321 // Since all our clients are done with this buffer, return it to the device layer
322 hardware::hidl_vec<BufferDesc_1_1> returnedBuffers;
323 returnedBuffers.resize(1);
324 returnedBuffers[0] = buffer;
325 mHwCamera->doneWithFrame_1_1(returnedBuffers);
326
327 // Counts a returned buffer
328 mUsageStats->framesReturned(returnedBuffers);
329 }
330 }
331
332 return Void();
333 }
334
335
336 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCameraStream follow.
deliverFrame(const BufferDesc_1_0 & buffer)337 Return<void> HalCamera::deliverFrame(const BufferDesc_1_0& buffer) {
338 /* Frames are delivered via deliverFrame_1_1 callback for clients that implement
339 * IEvsCameraStream v1.1 interfaces and therefore this method must not be
340 * used.
341 */
342 LOG(INFO) << "A delivered frame from EVS v1.0 HW module is rejected.";
343 mHwCamera->doneWithFrame(buffer);
344
345 // Reports a received and returned buffer
346 mUsageStats->framesReceived();
347 mUsageStats->framesReturned();
348
349 return Void();
350 }
351
352
353 // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCameraStream follow.
deliverFrame_1_1(const hardware::hidl_vec<BufferDesc_1_1> & buffer)354 Return<void> HalCamera::deliverFrame_1_1(const hardware::hidl_vec<BufferDesc_1_1>& buffer) {
355 LOG(VERBOSE) << "Received a frame";
356 // Frames are being forwarded to v1.1 clients only who requested new frame.
357 const auto timestamp = buffer[0].timestamp;
358 // TODO(b/145750636): For now, we are using a approximately half of 1 seconds / 30 frames = 33ms
359 // but this must be derived from current framerate.
360 constexpr int64_t kThreshold = 16 * 1e+3; // ms
361 unsigned frameDeliveriesV1 = 0;
362 {
363 // Handle frame requests from v1.1 clients
364 std::lock_guard<std::mutex> lock(mFrameMutex);
365 std::swap(mCurrentRequests, mNextRequests);
366 while (!mCurrentRequests->empty()) {
367 auto req = mCurrentRequests->front(); mCurrentRequests->pop_front();
368 sp<VirtualCamera> vCam = req.client.promote();
369 if (vCam == nullptr) {
370 // Ignore a client already dead.
371 continue;
372 } else if (timestamp - req.timestamp < kThreshold) {
373 // Skip current frame because it arrives too soon.
374 LOG(DEBUG) << "Skips a frame from " << getId();
375 mNextRequests->push_back(req);
376
377 // Reports a skipped frame
378 mUsageStats->framesSkippedToSync();
379 } else if (vCam != nullptr && vCam->deliverFrame(buffer[0])) {
380 // Forward a frame and move a timeline.
381 LOG(DEBUG) << getId() << " forwarded the buffer #" << buffer[0].bufferId;
382 ++frameDeliveriesV1;
383 }
384 }
385 }
386
387 // Reports the number of received buffers
388 mUsageStats->framesReceived(buffer);
389
390 // Frames are being forwarded to active v1.0 clients and v1.1 clients if we
391 // failed to create a timeline.
392 unsigned frameDeliveries = 0;
393 for (auto&& client : mClients) {
394 sp<VirtualCamera> vCam = client.promote();
395 if (vCam == nullptr || vCam->getVersion() > 0) {
396 continue;
397 }
398
399 if (vCam->deliverFrame(buffer[0])) {
400 ++frameDeliveries;
401 }
402 }
403
404 frameDeliveries += frameDeliveriesV1;
405 if (frameDeliveries < 1) {
406 // If none of our clients could accept the frame, then return it
407 // right away.
408 LOG(INFO) << "Trivially rejecting frame (" << buffer[0].bufferId
409 << ") from " << getId() << " with no acceptance";
410 mHwCamera->doneWithFrame_1_1(buffer);
411
412 // Reports a returned buffer
413 mUsageStats->framesReturned(buffer);
414 } else {
415 // Add an entry for this frame in our tracking list.
416 unsigned i;
417 for (i = 0; i < mFrames.size(); ++i) {
418 if (mFrames[i].refCount == 0) {
419 break;
420 }
421 }
422
423 if (i == mFrames.size()) {
424 mFrames.emplace_back(buffer[0].bufferId);
425 } else {
426 mFrames[i].frameId = buffer[0].bufferId;
427 }
428 mFrames[i].refCount = frameDeliveries;
429 }
430
431 return Void();
432 }
433
434
notify(const EvsEventDesc & event)435 Return<void> HalCamera::notify(const EvsEventDesc& event) {
436 LOG(DEBUG) << "Received an event id: " << static_cast<int32_t>(event.aType);
437 if(event.aType == EvsEventType::STREAM_STOPPED) {
438 // This event happens only when there is no more active client.
439 if (mStreamState != STOPPING) {
440 LOG(WARNING) << "Stream stopped unexpectedly";
441 }
442
443 mStreamState = STOPPED;
444 }
445
446 // Forward all other events to the clients
447 for (auto&& client : mClients) {
448 sp<VirtualCamera> vCam = client.promote();
449 if (vCam != nullptr) {
450 if (!vCam->notify(event)) {
451 LOG(INFO) << "Failed to forward an event";
452 }
453 }
454 }
455
456 return Void();
457 }
458
459
setMaster(sp<VirtualCamera> virtualCamera)460 Return<EvsResult> HalCamera::setMaster(sp<VirtualCamera> virtualCamera) {
461 if (mMaster == nullptr) {
462 LOG(DEBUG) << __FUNCTION__
463 << ": " << virtualCamera.get() << " becomes a master.";
464 mMaster = virtualCamera;
465 return EvsResult::OK;
466 } else {
467 LOG(INFO) << "This camera already has a master client.";
468 return EvsResult::OWNERSHIP_LOST;
469 }
470 }
471
472
forceMaster(sp<VirtualCamera> virtualCamera)473 Return<EvsResult> HalCamera::forceMaster(sp<VirtualCamera> virtualCamera) {
474 sp<VirtualCamera> prevMaster = mMaster.promote();
475 if (prevMaster == virtualCamera) {
476 LOG(DEBUG) << "Client " << virtualCamera.get()
477 << " is already a master client";
478 } else {
479 mMaster = virtualCamera;
480 if (prevMaster != nullptr) {
481 LOG(INFO) << "High priority client " << virtualCamera.get()
482 << " steals a master role from " << prevMaster.get();
483
484 /* Notify a previous master client the loss of a master role */
485 EvsEventDesc event;
486 event.aType = EvsEventType::MASTER_RELEASED;
487 if (!prevMaster->notify(event)) {
488 LOG(ERROR) << "Fail to deliver a master role lost notification";
489 }
490 }
491 }
492
493 return EvsResult::OK;
494 }
495
496
unsetMaster(sp<VirtualCamera> virtualCamera)497 Return<EvsResult> HalCamera::unsetMaster(sp<VirtualCamera> virtualCamera) {
498 if (mMaster.promote() != virtualCamera) {
499 return EvsResult::INVALID_ARG;
500 } else {
501 LOG(INFO) << "Unset a master camera client";
502 mMaster = nullptr;
503
504 /* Notify other clients that a master role becomes available. */
505 EvsEventDesc event;
506 event.aType = EvsEventType::MASTER_RELEASED;
507 auto cbResult = this->notify(event);
508 if (!cbResult.isOk()) {
509 LOG(ERROR) << "Fail to deliver a parameter change notification";
510 }
511
512 return EvsResult::OK;
513 }
514 }
515
516
setParameter(sp<VirtualCamera> virtualCamera,CameraParam id,int32_t & value)517 Return<EvsResult> HalCamera::setParameter(sp<VirtualCamera> virtualCamera,
518 CameraParam id, int32_t& value) {
519 EvsResult result = EvsResult::INVALID_ARG;
520 if (virtualCamera == mMaster.promote()) {
521 mHwCamera->setIntParameter(id, value,
522 [&result, &value](auto status, auto readValue) {
523 result = status;
524 value = readValue[0];
525 });
526
527 if (result == EvsResult::OK) {
528 /* Notify a parameter change */
529 EvsEventDesc event;
530 event.aType = EvsEventType::PARAMETER_CHANGED;
531 event.payload[0] = static_cast<uint32_t>(id);
532 event.payload[1] = static_cast<uint32_t>(value);
533 auto cbResult = this->notify(event);
534 if (!cbResult.isOk()) {
535 LOG(ERROR) << "Fail to deliver a parameter change notification";
536 }
537 }
538 } else {
539 LOG(WARNING) << "A parameter change request from a non-master client is declined.";
540
541 /* Read a current value of a requested camera parameter */
542 getParameter(id, value);
543 }
544
545 return result;
546 }
547
548
getParameter(CameraParam id,int32_t & value)549 Return<EvsResult> HalCamera::getParameter(CameraParam id, int32_t& value) {
550 EvsResult result = EvsResult::OK;
551 mHwCamera->getIntParameter(id, [&result, &value](auto status, auto readValue) {
552 result = status;
553 if (result == EvsResult::OK) {
554 value = readValue[0];
555 }
556 });
557
558 return result;
559 }
560
561
getStats() const562 CameraUsageStatsRecord HalCamera::getStats() const {
563 return mUsageStats->snapshot();
564 }
565
566
getStreamConfiguration() const567 Stream HalCamera::getStreamConfiguration() const {
568 return mStreamConfig;
569 }
570
571
toString(const char * indent) const572 std::string HalCamera::toString(const char* indent) const {
573 std::string buffer;
574
575 const auto timeElapsedMs = android::uptimeMillis() - mTimeCreatedMs;
576 StringAppendF(&buffer, "%sCreated: @%" PRId64 " (elapsed %" PRId64 " ms)\n",
577 indent, mTimeCreatedMs, timeElapsedMs);
578
579 std::string double_indent(indent);
580 double_indent += indent;
581 buffer += CameraUsageStats::toString(getStats(), double_indent.c_str());
582 for (auto&& client : mClients) {
583 auto handle = client.promote();
584 if (!handle) {
585 continue;
586 }
587
588 StringAppendF(&buffer, "%sClient %p\n",
589 indent, handle.get());
590 buffer += handle->toString(double_indent.c_str());
591 }
592
593 StringAppendF(&buffer, "%sMaster client: %p\n",
594 indent, mMaster.promote().get());
595
596 buffer += HalCamera::toString(mStreamConfig, indent);
597
598 return buffer;
599 }
600
601
toString(Stream configuration,const char * indent)602 std::string HalCamera::toString(Stream configuration, const char* indent) {
603 std::string streamInfo;
604 std::string double_indent(indent);
605 double_indent += indent;
606 StringAppendF(&streamInfo, "%sActive Stream Configuration\n"
607 "%sid: %d\n"
608 "%swidth: %d\n"
609 "%sheight: %d\n"
610 "%sformat: 0x%X\n"
611 "%susage: 0x%" PRIx64 "\n"
612 "%srotation: 0x%X\n\n",
613 indent,
614 double_indent.c_str(), configuration.id,
615 double_indent.c_str(), configuration.width,
616 double_indent.c_str(), configuration.height,
617 double_indent.c_str(), configuration.format,
618 double_indent.c_str(), configuration.usage,
619 double_indent.c_str(), configuration.rotation);
620
621 return streamInfo;
622 }
623
624
625 } // namespace implementation
626 } // namespace V1_1
627 } // namespace evs
628 } // namespace automotive
629 } // namespace android
630