1 /*
2 * Copyright (C) 2018 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 "ExtCamDevSsn@3.5"
18 #include <android/log.h>
19
20 #include <utils/Trace.h>
21 #include "ExternalCameraDeviceSession.h"
22
23 namespace android {
24 namespace hardware {
25 namespace camera {
26 namespace device {
27 namespace V3_5 {
28 namespace implementation {
29
ExternalCameraDeviceSession(const sp<V3_2::ICameraDeviceCallback> & callback,const ExternalCameraConfig & cfg,const std::vector<SupportedV4L2Format> & sortedFormats,const CroppingType & croppingType,const common::V1_0::helper::CameraMetadata & chars,const std::string & cameraId,unique_fd v4l2Fd)30 ExternalCameraDeviceSession::ExternalCameraDeviceSession(
31 const sp<V3_2::ICameraDeviceCallback>& callback,
32 const ExternalCameraConfig& cfg,
33 const std::vector<SupportedV4L2Format>& sortedFormats,
34 const CroppingType& croppingType,
35 const common::V1_0::helper::CameraMetadata& chars,
36 const std::string& cameraId,
37 unique_fd v4l2Fd) :
38 V3_4::implementation::ExternalCameraDeviceSession(
39 callback, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)) {
40
41 mCallback_3_5 = nullptr;
42
43 auto castResult = V3_5::ICameraDeviceCallback::castFrom(callback);
44 if (castResult.isOk()) {
45 sp<V3_5::ICameraDeviceCallback> callback3_5 = castResult;
46 if (callback3_5 != nullptr) {
47 mCallback_3_5 = callback3_5;
48 }
49 }
50
51 if (mCallback_3_5 != nullptr) {
52 mSupportBufMgr = true;
53 }
54 }
55
~ExternalCameraDeviceSession()56 ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {
57 closeOutputThreadImpl();
58 }
59
configureStreams_3_5(const StreamConfiguration & requestedConfiguration,ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb)60 Return<void> ExternalCameraDeviceSession::configureStreams_3_5(
61 const StreamConfiguration& requestedConfiguration,
62 ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb) {
63 return configureStreams_3_4(requestedConfiguration.v3_4, _hidl_cb);
64 }
65
signalStreamFlush(const hidl_vec<int32_t> &,uint32_t)66 Return<void> ExternalCameraDeviceSession::signalStreamFlush(
67 const hidl_vec<int32_t>& /*streamIds*/, uint32_t /*streamConfigCounter*/) {
68 return Void();
69 }
70
importRequestLocked(const CaptureRequest & request,hidl_vec<buffer_handle_t * > & allBufPtrs,hidl_vec<int> & allFences)71 Status ExternalCameraDeviceSession::importRequestLocked(
72 const CaptureRequest& request,
73 hidl_vec<buffer_handle_t*>& allBufPtrs,
74 hidl_vec<int>& allFences) {
75 if (mSupportBufMgr) {
76 return importRequestLockedImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ true);
77 }
78 return importRequestLockedImpl(request, allBufPtrs, allFences, /*allowEmptyBuf*/ false);
79 }
80
81
BufferRequestThread(wp<OutputThreadInterface> parent,sp<V3_5::ICameraDeviceCallback> callbacks)82 ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread(
83 wp<OutputThreadInterface> parent,
84 sp<V3_5::ICameraDeviceCallback> callbacks) :
85 mParent(parent),
86 mCallbacks(callbacks) {}
87
requestBufferStart(const std::vector<HalStreamBuffer> & bufReqs)88 int ExternalCameraDeviceSession::BufferRequestThread::requestBufferStart(
89 const std::vector<HalStreamBuffer>& bufReqs) {
90 if (bufReqs.empty()) {
91 ALOGE("%s: bufReqs is empty!", __FUNCTION__);
92 return -1;
93 }
94
95 {
96 std::lock_guard<std::mutex> lk(mLock);
97 if (mRequestingBuffer) {
98 ALOGE("%s: BufferRequestThread does not support more than one concurrent request!",
99 __FUNCTION__);
100 return -1;
101 }
102
103 mBufferReqs = bufReqs;
104 mRequestingBuffer = true;
105 }
106 mRequestCond.notify_one();
107 return 0;
108 }
109
waitForBufferRequestDone(std::vector<HalStreamBuffer> * outBufReq)110 int ExternalCameraDeviceSession::BufferRequestThread::waitForBufferRequestDone(
111 std::vector<HalStreamBuffer>* outBufReq) {
112 std::unique_lock<std::mutex> lk(mLock);
113 if (!mRequestingBuffer) {
114 ALOGE("%s: no pending buffer request!", __FUNCTION__);
115 return -1;
116 }
117
118 if (mPendingReturnBufferReqs.empty()) {
119 std::chrono::milliseconds timeout = std::chrono::milliseconds(kReqProcTimeoutMs);
120 auto st = mRequestDoneCond.wait_for(lk, timeout);
121 if (st == std::cv_status::timeout) {
122 ALOGE("%s: wait for buffer request finish timeout!", __FUNCTION__);
123 return -1;
124 }
125 }
126 mRequestingBuffer = false;
127 *outBufReq = std::move(mPendingReturnBufferReqs);
128 mPendingReturnBufferReqs.clear();
129 return 0;
130 }
131
waitForNextRequest()132 void ExternalCameraDeviceSession::BufferRequestThread::waitForNextRequest() {
133 ATRACE_CALL();
134 std::unique_lock<std::mutex> lk(mLock);
135 int waitTimes = 0;
136 while (mBufferReqs.empty()) {
137 if (exitPending()) {
138 return;
139 }
140 std::chrono::milliseconds timeout = std::chrono::milliseconds(kReqWaitTimeoutMs);
141 auto st = mRequestCond.wait_for(lk, timeout);
142 if (st == std::cv_status::timeout) {
143 waitTimes++;
144 if (waitTimes == kReqWaitTimesWarn) {
145 // BufferRequestThread just wait forever for new buffer request
146 // But it will print some periodic warning indicating it's waiting
147 ALOGV("%s: still waiting for new buffer request", __FUNCTION__);
148 waitTimes = 0;
149 }
150 }
151 }
152
153 // Fill in hidl BufferRequest
154 mHalBufferReqs.resize(mBufferReqs.size());
155 for (size_t i = 0; i < mHalBufferReqs.size(); i++) {
156 mHalBufferReqs[i].streamId = mBufferReqs[i].streamId;
157 mHalBufferReqs[i].numBuffersRequested = 1;
158 }
159 }
160
threadLoop()161 bool ExternalCameraDeviceSession::BufferRequestThread::threadLoop() {
162 waitForNextRequest();
163 if (exitPending()) {
164 return false;
165 }
166
167 ATRACE_BEGIN("HIDL requestStreamBuffers");
168 BufferRequestStatus status;
169 hidl_vec<StreamBufferRet> bufRets;
170 auto err = mCallbacks->requestStreamBuffers(mHalBufferReqs,
171 [&status, &bufRets]
172 (BufferRequestStatus s, const hidl_vec<StreamBufferRet>& rets) {
173 status = s;
174 bufRets = std::move(rets);
175 });
176 ATRACE_END();
177 if (!err.isOk()) {
178 ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
179 return false;
180 }
181
182 std::unique_lock<std::mutex> lk(mLock);
183 if (status == BufferRequestStatus::OK || status == BufferRequestStatus::FAILED_PARTIAL) {
184 if (bufRets.size() != mHalBufferReqs.size()) {
185 ALOGE("%s: expect %zu buffer requests returned, only got %zu",
186 __FUNCTION__, mHalBufferReqs.size(), bufRets.size());
187 return false;
188 }
189
190 auto parent = mParent.promote();
191 if (parent == nullptr) {
192 ALOGE("%s: session has been disconnected!", __FUNCTION__);
193 return false;
194 }
195
196 hidl_vec<int> importedFences;
197 importedFences.resize(bufRets.size());
198 for (size_t i = 0; i < bufRets.size(); i++) {
199 int streamId = bufRets[i].streamId;
200 switch (bufRets[i].val.getDiscriminator()) {
201 case StreamBuffersVal::hidl_discriminator::error:
202 continue;
203 case StreamBuffersVal::hidl_discriminator::buffers: {
204 const hidl_vec<V3_2::StreamBuffer>& hBufs = bufRets[i].val.buffers();
205 if (hBufs.size() != 1) {
206 ALOGE("%s: expect 1 buffer returned, got %zu!", __FUNCTION__, hBufs.size());
207 return false;
208 }
209 const V3_2::StreamBuffer& hBuf = hBufs[0];
210
211 mBufferReqs[i].bufferId = hBuf.bufferId;
212 // TODO: create a batch import API so we don't need to lock/unlock mCbsLock
213 // repeatedly?
214 lk.unlock();
215 Status s = parent->importBuffer(streamId,
216 hBuf.bufferId, hBuf.buffer.getNativeHandle(),
217 /*out*/&mBufferReqs[i].bufPtr,
218 /*allowEmptyBuf*/false);
219 lk.lock();
220
221 if (s != Status::OK) {
222 ALOGE("%s: stream %d import buffer failed!", __FUNCTION__, streamId);
223 cleanupInflightFences(importedFences, i - 1);
224 return false;
225 }
226 if (!sHandleImporter.importFence(hBuf.acquireFence,
227 mBufferReqs[i].acquireFence)) {
228 ALOGE("%s: stream %d import fence failed!", __FUNCTION__, streamId);
229 cleanupInflightFences(importedFences, i - 1);
230 return false;
231 }
232 importedFences[i] = mBufferReqs[i].acquireFence;
233 }
234 break;
235 default:
236 ALOGE("%s: unkown StreamBuffersVal discrimator!", __FUNCTION__);
237 return false;
238 }
239 }
240 } else {
241 ALOGE("%s: requestStreamBuffers call failed!", __FUNCTION__);
242 }
243
244 mPendingReturnBufferReqs = std::move(mBufferReqs);
245 mBufferReqs.clear();
246
247 lk.unlock();
248 mRequestDoneCond.notify_one();
249 return true;
250 }
251
initOutputThread()252 void ExternalCameraDeviceSession::initOutputThread() {
253 if (mSupportBufMgr) {
254 mBufferRequestThread = new BufferRequestThread(this, mCallback_3_5);
255 mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY);
256 }
257 mOutputThread = new OutputThread(
258 this, mCroppingType, mCameraCharacteristics, mBufferRequestThread);
259 }
260
closeOutputThreadImpl()261 void ExternalCameraDeviceSession::closeOutputThreadImpl() {
262 if (mBufferRequestThread) {
263 mBufferRequestThread->requestExit();
264 mBufferRequestThread->join();
265 mBufferRequestThread.clear();
266 }
267 }
268
closeOutputThread()269 void ExternalCameraDeviceSession::closeOutputThread() {
270 closeOutputThreadImpl();
271 V3_4::implementation::ExternalCameraDeviceSession::closeOutputThread();
272 }
273
OutputThread(wp<OutputThreadInterface> parent,CroppingType ct,const common::V1_0::helper::CameraMetadata & chars,sp<BufferRequestThread> bufReqThread)274 ExternalCameraDeviceSession::OutputThread::OutputThread(
275 wp<OutputThreadInterface> parent,
276 CroppingType ct,
277 const common::V1_0::helper::CameraMetadata& chars,
278 sp<BufferRequestThread> bufReqThread) :
279 V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct, chars),
280 mBufferRequestThread(bufReqThread) {}
281
~OutputThread()282 ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
283
requestBufferStart(const std::vector<HalStreamBuffer> & bufs)284 int ExternalCameraDeviceSession::OutputThread::requestBufferStart(
285 const std::vector<HalStreamBuffer>& bufs) {
286 if (mBufferRequestThread != nullptr) {
287 return mBufferRequestThread->requestBufferStart(bufs);
288 }
289 return 0;
290 }
291
waitForBufferRequestDone(std::vector<HalStreamBuffer> * outBufs)292 int ExternalCameraDeviceSession::OutputThread::waitForBufferRequestDone(
293 /*out*/std::vector<HalStreamBuffer>* outBufs) {
294 if (mBufferRequestThread != nullptr) {
295 return mBufferRequestThread->waitForBufferRequestDone(outBufs);
296 }
297 return 0;
298 }
299
isReconfigurationRequired(const V3_2::CameraMetadata &,const V3_2::CameraMetadata &,ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb)300 Return<void> ExternalCameraDeviceSession::isReconfigurationRequired(
301 const V3_2::CameraMetadata& /*oldSessionParams*/,
302 const V3_2::CameraMetadata& /*newSessionParams*/,
303 ICameraDeviceSession::isReconfigurationRequired_cb _hidl_cb) {
304 //Stub implementation
305 _hidl_cb(Status::OK, true);
306 return Void();
307 }
308
309 } // namespace implementation
310 } // namespace V3_5
311 } // namespace device
312 } // namespace camera
313 } // namespace hardware
314 } // namespace android
315