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