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