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