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 #include "VirtualCamera.h"
19 #include "Enumerator.h"
20 
21 #include <ui/GraphicBufferAllocator.h>
22 #include <ui/GraphicBufferMapper.h>
23 
24 
25 namespace android {
26 namespace automotive {
27 namespace evs {
28 namespace V1_0 {
29 namespace implementation {
30 
31 
32 // TODO:  We need to hook up death monitoring to detect stream death so we can attempt a reconnect
33 
34 
makeVirtualCamera()35 sp<VirtualCamera> HalCamera::makeVirtualCamera() {
36 
37     // Create the client camera interface object
38     sp<VirtualCamera> client = new VirtualCamera(this);
39     if (client == nullptr) {
40         ALOGE("Failed to create client camera object");
41         return nullptr;
42     }
43 
44     // Make sure we have enough buffers available for all our clients
45     if (!changeFramesInFlight(client->getAllowedBuffers())) {
46         // Gah!  We couldn't get enough buffers, so we can't support this client
47         // Null the pointer, dropping our reference, thus destroying the client object
48         client = nullptr;
49         return nullptr;
50     }
51 
52     // Add this client to our ownership list via weak pointer
53     mClients.push_back(client);
54 
55     // Return the strong pointer to the client
56     return client;
57 }
58 
59 
disownVirtualCamera(sp<VirtualCamera> virtualCamera)60 void HalCamera::disownVirtualCamera(sp<VirtualCamera> virtualCamera) {
61     // Ignore calls with null pointers
62     if (virtualCamera.get() == nullptr) {
63         ALOGW("Ignoring disownVirtualCamera call with null pointer");
64         return;
65     }
66 
67     // Make sure the virtual camera's stream is stopped
68     virtualCamera->stopVideoStream();
69 
70     // Remove the virtual camera from our client list
71     unsigned clientCount = mClients.size();
72     mClients.remove(virtualCamera);
73     if (clientCount != mClients.size() + 1) {
74         ALOGE("Couldn't find camera in our client list to remove it");
75     }
76     virtualCamera->shutdown();
77 
78     // Recompute the number of buffers required with the target camera removed from the list
79     if (!changeFramesInFlight(0)) {
80         ALOGE("Error when trying to reduce the in flight buffer count");
81     }
82 }
83 
84 
changeFramesInFlight(int delta)85 bool HalCamera::changeFramesInFlight(int delta) {
86     // Walk all our clients and count their currently required frames
87     unsigned bufferCount = 0;
88     for (auto&& client :  mClients) {
89         sp<VirtualCamera> virtCam = client.promote();
90         if (virtCam != nullptr) {
91             bufferCount += virtCam->getAllowedBuffers();
92         }
93     }
94 
95     // Add the requested delta
96     bufferCount += delta;
97 
98     // Never drop below 1 buffer -- even if all client cameras get closed
99     if (bufferCount < 1) {
100         bufferCount = 1;
101     }
102 
103     // Ask the hardware for the resulting buffer count
104     Return<EvsResult> result = mHwCamera->setMaxFramesInFlight(bufferCount);
105     bool success = (result.isOk() && result == EvsResult::OK);
106 
107     // Update the size of our array of outstanding frame records
108     if (success) {
109         std::vector<FrameRecord> newRecords;
110         newRecords.reserve(bufferCount);
111 
112         // Copy and compact the old records that are still active
113         for (const auto& rec : mFrames) {
114             if (rec.refCount > 0) {
115                 newRecords.emplace_back(rec);
116             }
117         }
118         if (newRecords.size() > (unsigned)bufferCount) {
119             ALOGW("We found more frames in use than requested.");
120         }
121 
122         mFrames.swap(newRecords);
123     }
124 
125     return success;
126 }
127 
128 
clientStreamStarting()129 Return<EvsResult> HalCamera::clientStreamStarting() {
130     Return<EvsResult> result = EvsResult::OK;
131 
132     if (mStreamState == STOPPED) {
133         mStreamState = RUNNING;
134         result = mHwCamera->startVideoStream(this);
135     }
136 
137     return result;
138 }
139 
140 
clientStreamEnding()141 void HalCamera::clientStreamEnding() {
142     // Do we still have a running client?
143     bool stillRunning = false;
144     for (auto&& client : mClients) {
145         sp<VirtualCamera> virtCam = client.promote();
146         if (virtCam != nullptr) {
147             stillRunning |= virtCam->isStreaming();
148         }
149     }
150 
151     // If not, then stop the hardware stream
152     if (!stillRunning) {
153         mStreamState = STOPPED;
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