1 /*
2 * Copyright (C) 2016 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 "HalCamera.h"
18
19 #include "Enumerator.h"
20 #include "VirtualCamera.h"
21
22 #include <ui/GraphicBufferAllocator.h>
23 #include <ui/GraphicBufferMapper.h>
24
25 namespace android {
26 namespace automotive {
27 namespace evs {
28 namespace V1_0 {
29 namespace implementation {
30
31 // TODO: We need to hook up death monitoring to detect stream death so we can attempt a reconnect
32
makeVirtualCamera()33 sp<VirtualCamera> HalCamera::makeVirtualCamera() {
34 // Create the client camera interface object
35 sp<VirtualCamera> client = new VirtualCamera(this);
36 if (client == nullptr) {
37 ALOGE("Failed to create client camera object");
38 return nullptr;
39 }
40
41 // Make sure we have enough buffers available for all our clients
42 if (!changeFramesInFlight(client->getAllowedBuffers())) {
43 // Gah! We couldn't get enough buffers, so we can't support this client
44 // Null the pointer, dropping our reference, thus destroying the client object
45 client = nullptr;
46 return nullptr;
47 }
48
49 // Add this client to our ownership list via weak pointer
50 mClients.push_back(client);
51
52 // Return the strong pointer to the client
53 return client;
54 }
55
disownVirtualCamera(sp<VirtualCamera> virtualCamera)56 void HalCamera::disownVirtualCamera(sp<VirtualCamera> virtualCamera) {
57 // Ignore calls with null pointers
58 if (virtualCamera.get() == nullptr) {
59 ALOGW("Ignoring disownVirtualCamera call with null pointer");
60 return;
61 }
62
63 // Make sure the virtual camera's stream is stopped
64 virtualCamera->stopVideoStream();
65
66 // Remove the virtual camera from our client list
67 unsigned clientCount = mClients.size();
68 mClients.remove(virtualCamera);
69 if (clientCount != mClients.size() + 1) {
70 ALOGE("Couldn't find camera in our client list to remove it");
71 }
72 virtualCamera->shutdown();
73
74 // Recompute the number of buffers required with the target camera removed from the list
75 if (!changeFramesInFlight(0)) {
76 ALOGE("Error when trying to reduce the in flight buffer count");
77 }
78 }
79
changeFramesInFlight(int delta)80 bool HalCamera::changeFramesInFlight(int delta) {
81 // Walk all our clients and count their currently required frames
82 unsigned bufferCount = 0;
83 for (auto&& client : mClients) {
84 sp<VirtualCamera> virtCam = client.promote();
85 if (virtCam != nullptr) {
86 bufferCount += virtCam->getAllowedBuffers();
87 }
88 }
89
90 // Add the requested delta
91 bufferCount += delta;
92
93 // Never drop below 1 buffer -- even if all client cameras get closed
94 if (bufferCount < 1) {
95 bufferCount = 1;
96 }
97
98 // Ask the hardware for the resulting buffer count
99 Return<EvsResult> result = mHwCamera->setMaxFramesInFlight(bufferCount);
100 bool success = (result.isOk() && result == EvsResult::OK);
101
102 // Update the size of our array of outstanding frame records
103 if (success) {
104 std::vector<FrameRecord> newRecords;
105 newRecords.reserve(bufferCount);
106
107 // Copy and compact the old records that are still active
108 for (const auto& rec : mFrames) {
109 if (rec.refCount > 0) {
110 newRecords.emplace_back(rec);
111 }
112 }
113 if (newRecords.size() > (unsigned)bufferCount) {
114 ALOGW("We found more frames in use than requested.");
115 }
116
117 mFrames.swap(newRecords);
118 }
119
120 return success;
121 }
122
clientStreamStarting()123 Return<EvsResult> HalCamera::clientStreamStarting() {
124 Return<EvsResult> result = EvsResult::OK;
125
126 if (mStreamState == STOPPED) {
127 mStreamState = RUNNING;
128 result = mHwCamera->startVideoStream(this);
129 }
130
131 return result;
132 }
133
clientStreamEnding()134 void HalCamera::clientStreamEnding() {
135 // Do we still have a running client?
136 bool stillRunning = false;
137 for (auto&& client : mClients) {
138 sp<VirtualCamera> virtCam = client.promote();
139 if (virtCam != nullptr) {
140 stillRunning |= virtCam->isStreaming();
141 }
142 }
143
144 // If not, then stop the hardware stream
145 if (!stillRunning) {
146 mStreamState = STOPPED;
147 mHwCamera->stopVideoStream();
148 }
149 }
150
doneWithFrame(const BufferDesc & buffer)151 Return<void> HalCamera::doneWithFrame(const BufferDesc& buffer) {
152 // Find this frame in our list of outstanding frames
153 unsigned i;
154 for (i = 0; i < mFrames.size(); i++) {
155 if (mFrames[i].frameId == buffer.bufferId) {
156 break;
157 }
158 }
159 if (i == mFrames.size()) {
160 ALOGE("We got a frame back with an ID we don't recognize!");
161 } else {
162 // Are there still clients using this buffer?
163 mFrames[i].refCount--;
164 if (mFrames[i].refCount <= 0) {
165 // Since all our clients are done with this buffer, return it to the device layer
166 mHwCamera->doneWithFrame(buffer);
167 }
168 }
169
170 return Void();
171 }
172
deliverFrame(const BufferDesc & buffer)173 Return<void> HalCamera::deliverFrame(const BufferDesc& buffer) {
174 // Run through all our clients and deliver this frame to any who are eligible
175 unsigned frameDeliveries = 0;
176 for (auto&& client : mClients) {
177 sp<VirtualCamera> virtCam = client.promote();
178 if (virtCam != nullptr) {
179 if (virtCam->deliverFrame(buffer)) {
180 frameDeliveries++;
181 }
182 }
183 }
184
185 if (frameDeliveries < 1) {
186 // If none of our clients could accept the frame, then return it right away
187 ALOGI("Trivially rejecting frame with no acceptances");
188 mHwCamera->doneWithFrame(buffer);
189 } else {
190 // Add an entry for this frame in our tracking list
191 unsigned i;
192 for (i = 0; i < mFrames.size(); i++) {
193 if (mFrames[i].refCount == 0) {
194 break;
195 }
196 }
197 if (i == mFrames.size()) {
198 mFrames.emplace_back(buffer.bufferId);
199 } else {
200 mFrames[i].frameId = buffer.bufferId;
201 }
202 mFrames[i].refCount = frameDeliveries;
203 }
204
205 return Void();
206 }
207
208 } // namespace implementation
209 } // namespace V1_0
210 } // namespace evs
211 } // namespace automotive
212 } // namespace android
213