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