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 if (mStreamState == RUNNING) {
125 // This camera is already active.
126 return EvsResult::OK;
127 }
128
129 if (mStreamState == STOPPED) {
130 Return<EvsResult> status = mHwCamera->startVideoStream(this);
131 if (status.isOk() && status == EvsResult::OK) {
132 mStreamState = RUNNING;
133 }
134 return status;
135 }
136
137 // We cannot start a video stream.
138 if (mStreamState == STOPPING) {
139 ALOGE("A device is busy; stopping a current video stream.");
140 }
141 return EvsResult::UNDERLYING_SERVICE_ERROR;
142 }
143
clientStreamEnding()144 void HalCamera::clientStreamEnding() {
145 // Do we still have a running client?
146 bool stillRunning = false;
147 for (auto&& client : mClients) {
148 sp<VirtualCamera> virtCam = client.promote();
149 if (virtCam != nullptr) {
150 stillRunning |= virtCam->isStreaming();
151 }
152 }
153
154 // If not, then stop the hardware stream
155 if (!stillRunning) {
156 mStreamState = STOPPED;
157 mHwCamera->stopVideoStream();
158 }
159 }
160
doneWithFrame(const BufferDesc & buffer)161 Return<void> HalCamera::doneWithFrame(const BufferDesc& buffer) {
162 // Find this frame in our list of outstanding frames
163 unsigned i;
164 for (i = 0; i < mFrames.size(); i++) {
165 if (mFrames[i].frameId == buffer.bufferId) {
166 break;
167 }
168 }
169
170 if (i == mFrames.size()) {
171 ALOGE("We got a frame back with an ID we don't recognize!");
172 return {};
173 }
174
175 if (mFrames[i].refCount < 1) {
176 ALOGW("We got a frame that refcount is already zero.");
177 return {};
178 }
179
180 // Are there still clients using this buffer?
181 mFrames[i].refCount--;
182 if (mFrames[i].refCount == 0) {
183 // Since all our clients are done with this buffer, return it to the device layer
184 mHwCamera->doneWithFrame(buffer);
185 }
186
187 return Void();
188 }
189
deliverFrame(const BufferDesc & buffer)190 Return<void> HalCamera::deliverFrame(const BufferDesc& buffer) {
191 // Run through all our clients and deliver this frame to any who are eligible
192 unsigned frameDeliveries = 0;
193 for (auto&& client : mClients) {
194 sp<VirtualCamera> virtCam = client.promote();
195 if (virtCam != nullptr) {
196 if (virtCam->deliverFrame(buffer)) {
197 frameDeliveries++;
198 }
199 }
200 }
201
202 if (frameDeliveries < 1) {
203 // If none of our clients could accept the frame, then return it right away
204 ALOGI("Trivially rejecting frame with no acceptances");
205 mHwCamera->doneWithFrame(buffer);
206 } else {
207 // Add an entry for this frame in our tracking list
208 unsigned i;
209 for (i = 0; i < mFrames.size(); i++) {
210 if (mFrames[i].refCount == 0) {
211 break;
212 }
213 }
214 if (i == mFrames.size()) {
215 mFrames.emplace_back(buffer.bufferId);
216 } else {
217 mFrames[i].frameId = buffer.bufferId;
218 }
219 mFrames[i].refCount = frameDeliveries;
220 }
221
222 return Void();
223 }
224
225 } // namespace implementation
226 } // namespace V1_0
227 } // namespace evs
228 } // namespace automotive
229 } // namespace android
230