1 /* 2 * Copyright (C) 2014 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 package android.hardware.camera2.impl; 17 18 import android.hardware.camera2.CameraAccessException; 19 import android.hardware.camera2.CameraCaptureSession; 20 import android.hardware.camera2.CameraDevice; 21 import android.hardware.camera2.CaptureRequest; 22 import android.hardware.camera2.ICameraDeviceUser; 23 import android.hardware.camera2.params.OutputConfiguration; 24 import android.hardware.camera2.utils.TaskDrainer; 25 import android.hardware.camera2.utils.TaskSingleDrainer; 26 import android.os.Binder; 27 import android.os.Handler; 28 import android.util.Log; 29 import android.view.Surface; 30 31 import java.util.Arrays; 32 import java.util.List; 33 import java.util.concurrent.Executor; 34 35 import static android.hardware.camera2.impl.CameraDeviceImpl.checkHandler; 36 import static com.android.internal.util.Preconditions.*; 37 38 public class CameraCaptureSessionImpl extends CameraCaptureSession 39 implements CameraCaptureSessionCore { 40 private static final String TAG = "CameraCaptureSession"; 41 private static final boolean DEBUG = false; 42 43 /** Simple integer ID for session for debugging */ 44 private final int mId; 45 private final String mIdString; 46 47 /** Input surface configured by native camera framework based on user-specified configuration */ 48 private final Surface mInput; 49 /** 50 * User-specified state callback, used for outgoing events; calls to this object will be 51 * automatically invoked via {@code mStateExecutor}. 52 */ 53 private final CameraCaptureSession.StateCallback mStateCallback; 54 /** User-specified state executor used for outgoing state callback events */ 55 private final Executor mStateExecutor; 56 57 /** Internal camera device; used to translate calls into existing deprecated API */ 58 private final android.hardware.camera2.impl.CameraDeviceImpl mDeviceImpl; 59 /** Internal executor; used for all incoming events to preserve total order */ 60 private final Executor mDeviceExecutor; 61 62 /** Drain Sequence IDs which have been queued but not yet finished with aborted/completed */ 63 private final TaskDrainer<Integer> mSequenceDrainer; 64 /** Drain state transitions from ACTIVE -> IDLE */ 65 private final TaskSingleDrainer mIdleDrainer; 66 /** Drain state transitions from BUSY -> IDLE */ 67 private final TaskSingleDrainer mAbortDrainer; 68 69 /** This session is closed; all further calls will throw ISE */ 70 private boolean mClosed = false; 71 /** This session failed to be configured successfully */ 72 private final boolean mConfigureSuccess; 73 /** Do not unconfigure if this is set; another session will overwrite configuration */ 74 private boolean mSkipUnconfigure = false; 75 76 /** Is the session in the process of aborting? Pay attention to BUSY->IDLE transitions. */ 77 private volatile boolean mAborting; 78 79 /** 80 * Create a new CameraCaptureSession. 81 * 82 * <p>The camera device must already be in the {@code IDLE} state when this is invoked. 83 * There must be no pending actions 84 * (e.g. no pending captures, no repeating requests, no flush).</p> 85 */ CameraCaptureSessionImpl(int id, Surface input, CameraCaptureSession.StateCallback callback, Executor stateExecutor, android.hardware.camera2.impl.CameraDeviceImpl deviceImpl, Executor deviceStateExecutor, boolean configureSuccess)86 CameraCaptureSessionImpl(int id, Surface input, 87 CameraCaptureSession.StateCallback callback, Executor stateExecutor, 88 android.hardware.camera2.impl.CameraDeviceImpl deviceImpl, 89 Executor deviceStateExecutor, boolean configureSuccess) { 90 if (callback == null) { 91 throw new IllegalArgumentException("callback must not be null"); 92 } 93 94 mId = id; 95 mIdString = String.format("Session %d: ", mId); 96 97 mInput = input; 98 mStateExecutor = checkNotNull(stateExecutor, "stateExecutor must not be null"); 99 mStateCallback = createUserStateCallbackProxy(mStateExecutor, callback); 100 101 mDeviceExecutor = checkNotNull(deviceStateExecutor, 102 "deviceStateExecutor must not be null"); 103 mDeviceImpl = checkNotNull(deviceImpl, "deviceImpl must not be null"); 104 105 /* 106 * Use the same handler as the device's StateCallback for all the internal coming events 107 * 108 * This ensures total ordering between CameraDevice.StateCallback and 109 * CameraDeviceImpl.CaptureCallback events. 110 */ 111 mSequenceDrainer = new TaskDrainer<>(mDeviceExecutor, new SequenceDrainListener(), 112 /*name*/"seq"); 113 mIdleDrainer = new TaskSingleDrainer(mDeviceExecutor, new IdleDrainListener(), 114 /*name*/"idle"); 115 mAbortDrainer = new TaskSingleDrainer(mDeviceExecutor, new AbortDrainListener(), 116 /*name*/"abort"); 117 118 // CameraDevice should call configureOutputs and have it finish before constructing us 119 120 if (configureSuccess) { 121 mStateCallback.onConfigured(this); 122 if (DEBUG) Log.v(TAG, mIdString + "Created session successfully"); 123 mConfigureSuccess = true; 124 } else { 125 mStateCallback.onConfigureFailed(this); 126 mClosed = true; // do not fire any other callbacks, do not allow any other work 127 Log.e(TAG, mIdString + "Failed to create capture session; configuration failed"); 128 mConfigureSuccess = false; 129 } 130 } 131 132 @Override getDevice()133 public CameraDevice getDevice() { 134 return mDeviceImpl; 135 } 136 137 @Override prepare(Surface surface)138 public void prepare(Surface surface) throws CameraAccessException { 139 mDeviceImpl.prepare(surface); 140 } 141 142 @Override prepare(int maxCount, Surface surface)143 public void prepare(int maxCount, Surface surface) throws CameraAccessException { 144 mDeviceImpl.prepare(maxCount, surface); 145 } 146 147 @Override tearDown(Surface surface)148 public void tearDown(Surface surface) throws CameraAccessException { 149 mDeviceImpl.tearDown(surface); 150 } 151 152 @Override finalizeOutputConfigurations( List<OutputConfiguration> outputConfigs)153 public void finalizeOutputConfigurations( 154 List<OutputConfiguration> outputConfigs) throws CameraAccessException { 155 mDeviceImpl.finalizeOutputConfigs(outputConfigs); 156 } 157 158 @Override capture(CaptureRequest request, CaptureCallback callback, Handler handler)159 public int capture(CaptureRequest request, CaptureCallback callback, 160 Handler handler) throws CameraAccessException { 161 checkCaptureRequest(request); 162 163 synchronized (mDeviceImpl.mInterfaceLock) { 164 checkNotClosed(); 165 166 handler = checkHandler(handler, callback); 167 168 if (DEBUG) { 169 Log.v(TAG, mIdString + "capture - request " + request + ", callback " + callback + 170 " handler " + handler); 171 } 172 173 return addPendingSequence(mDeviceImpl.capture(request, 174 createCaptureCallbackProxy(handler, callback), mDeviceExecutor)); 175 } 176 } 177 178 @Override captureSingleRequest(CaptureRequest request, Executor executor, CaptureCallback callback)179 public int captureSingleRequest(CaptureRequest request, Executor executor, 180 CaptureCallback callback) throws CameraAccessException { 181 if (executor == null) { 182 throw new IllegalArgumentException("executor must not be null"); 183 } else if (callback == null) { 184 throw new IllegalArgumentException("callback must not be null"); 185 } 186 checkCaptureRequest(request); 187 188 synchronized (mDeviceImpl.mInterfaceLock) { 189 checkNotClosed(); 190 191 executor = CameraDeviceImpl.checkExecutor(executor, callback); 192 193 if (DEBUG) { 194 Log.v(TAG, mIdString + "capture - request " + request + ", callback " + callback + 195 " executor " + executor); 196 } 197 198 return addPendingSequence(mDeviceImpl.capture(request, 199 createCaptureCallbackProxyWithExecutor(executor, callback), mDeviceExecutor)); 200 } 201 } 202 checkCaptureRequest(CaptureRequest request)203 private void checkCaptureRequest(CaptureRequest request) { 204 if (request == null) { 205 throw new IllegalArgumentException("request must not be null"); 206 } else if (request.isReprocess() && !isReprocessable()) { 207 throw new IllegalArgumentException("this capture session cannot handle reprocess " + 208 "requests"); 209 } else if (request.isReprocess() && request.getReprocessableSessionId() != mId) { 210 throw new IllegalArgumentException("capture request was created for another session"); 211 } 212 } 213 214 @Override captureBurst(List<CaptureRequest> requests, CaptureCallback callback, Handler handler)215 public int captureBurst(List<CaptureRequest> requests, CaptureCallback callback, 216 Handler handler) throws CameraAccessException { 217 checkCaptureRequests(requests); 218 219 synchronized (mDeviceImpl.mInterfaceLock) { 220 checkNotClosed(); 221 222 handler = checkHandler(handler, callback); 223 224 if (DEBUG) { 225 CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]); 226 Log.v(TAG, mIdString + "captureBurst - requests " + Arrays.toString(requestArray) + 227 ", callback " + callback + " handler " + handler); 228 } 229 230 return addPendingSequence(mDeviceImpl.captureBurst(requests, 231 createCaptureCallbackProxy(handler, callback), mDeviceExecutor)); 232 } 233 } 234 235 @Override captureBurstRequests(List<CaptureRequest> requests, Executor executor, CaptureCallback callback)236 public int captureBurstRequests(List<CaptureRequest> requests, Executor executor, 237 CaptureCallback callback) throws CameraAccessException { 238 if (executor == null) { 239 throw new IllegalArgumentException("executor must not be null"); 240 } else if (callback == null) { 241 throw new IllegalArgumentException("callback must not be null"); 242 } 243 checkCaptureRequests(requests); 244 245 synchronized (mDeviceImpl.mInterfaceLock) { 246 checkNotClosed(); 247 248 executor = CameraDeviceImpl.checkExecutor(executor, callback); 249 250 if (DEBUG) { 251 CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]); 252 Log.v(TAG, mIdString + "captureBurst - requests " + Arrays.toString(requestArray) + 253 ", callback " + callback + " executor " + executor); 254 } 255 256 return addPendingSequence(mDeviceImpl.captureBurst(requests, 257 createCaptureCallbackProxyWithExecutor(executor, callback), mDeviceExecutor)); 258 } 259 } 260 checkCaptureRequests(List<CaptureRequest> requests)261 private void checkCaptureRequests(List<CaptureRequest> requests) { 262 if (requests == null) { 263 throw new IllegalArgumentException("Requests must not be null"); 264 } else if (requests.isEmpty()) { 265 throw new IllegalArgumentException("Requests must have at least one element"); 266 } 267 268 for (CaptureRequest request : requests) { 269 if (request.isReprocess()) { 270 if (!isReprocessable()) { 271 throw new IllegalArgumentException("This capture session cannot handle " + 272 "reprocess requests"); 273 } else if (request.getReprocessableSessionId() != mId) { 274 throw new IllegalArgumentException("Capture request was created for another " + 275 "session"); 276 } 277 } 278 } 279 280 } 281 282 @Override setRepeatingRequest(CaptureRequest request, CaptureCallback callback, Handler handler)283 public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback, 284 Handler handler) throws CameraAccessException { 285 checkRepeatingRequest(request); 286 287 synchronized (mDeviceImpl.mInterfaceLock) { 288 checkNotClosed(); 289 290 handler = checkHandler(handler, callback); 291 292 if (DEBUG) { 293 Log.v(TAG, mIdString + "setRepeatingRequest - request " + request + ", callback " + 294 callback + " handler" + " " + handler); 295 } 296 297 return addPendingSequence(mDeviceImpl.setRepeatingRequest(request, 298 createCaptureCallbackProxy(handler, callback), mDeviceExecutor)); 299 } 300 } 301 302 @Override setSingleRepeatingRequest(CaptureRequest request, Executor executor, CaptureCallback callback)303 public int setSingleRepeatingRequest(CaptureRequest request, Executor executor, 304 CaptureCallback callback) throws CameraAccessException { 305 if (executor == null) { 306 throw new IllegalArgumentException("executor must not be null"); 307 } else if (callback == null) { 308 throw new IllegalArgumentException("callback must not be null"); 309 } 310 checkRepeatingRequest(request); 311 312 synchronized (mDeviceImpl.mInterfaceLock) { 313 checkNotClosed(); 314 315 executor = CameraDeviceImpl.checkExecutor(executor, callback); 316 317 if (DEBUG) { 318 Log.v(TAG, mIdString + "setRepeatingRequest - request " + request + ", callback " + 319 callback + " executor" + " " + executor); 320 } 321 322 return addPendingSequence(mDeviceImpl.setRepeatingRequest(request, 323 createCaptureCallbackProxyWithExecutor(executor, callback), mDeviceExecutor)); 324 } 325 } 326 checkRepeatingRequest(CaptureRequest request)327 private void checkRepeatingRequest(CaptureRequest request) { 328 if (request == null) { 329 throw new IllegalArgumentException("request must not be null"); 330 } else if (request.isReprocess()) { 331 throw new IllegalArgumentException("repeating reprocess requests are not supported"); 332 } 333 } 334 335 @Override setRepeatingBurst(List<CaptureRequest> requests, CaptureCallback callback, Handler handler)336 public int setRepeatingBurst(List<CaptureRequest> requests, 337 CaptureCallback callback, Handler handler) throws CameraAccessException { 338 checkRepeatingRequests(requests); 339 340 synchronized (mDeviceImpl.mInterfaceLock) { 341 checkNotClosed(); 342 343 handler = checkHandler(handler, callback); 344 345 if (DEBUG) { 346 CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]); 347 Log.v(TAG, mIdString + "setRepeatingBurst - requests " + 348 Arrays.toString(requestArray) + ", callback " + callback + 349 " handler" + "" + handler); 350 } 351 352 return addPendingSequence(mDeviceImpl.setRepeatingBurst(requests, 353 createCaptureCallbackProxy(handler, callback), mDeviceExecutor)); 354 } 355 } 356 357 @Override setRepeatingBurstRequests(List<CaptureRequest> requests, Executor executor, CaptureCallback callback)358 public int setRepeatingBurstRequests(List<CaptureRequest> requests, Executor executor, 359 CaptureCallback callback) throws CameraAccessException { 360 if (executor == null) { 361 throw new IllegalArgumentException("executor must not be null"); 362 } else if (callback == null) { 363 throw new IllegalArgumentException("callback must not be null"); 364 } 365 checkRepeatingRequests(requests); 366 367 synchronized (mDeviceImpl.mInterfaceLock) { 368 checkNotClosed(); 369 370 executor = CameraDeviceImpl.checkExecutor(executor, callback); 371 372 if (DEBUG) { 373 CaptureRequest[] requestArray = requests.toArray(new CaptureRequest[0]); 374 Log.v(TAG, mIdString + "setRepeatingBurst - requests " + 375 Arrays.toString(requestArray) + ", callback " + callback + 376 " executor" + "" + executor); 377 } 378 379 return addPendingSequence(mDeviceImpl.setRepeatingBurst(requests, 380 createCaptureCallbackProxyWithExecutor(executor, callback), mDeviceExecutor)); 381 } 382 } 383 checkRepeatingRequests(List<CaptureRequest> requests)384 private void checkRepeatingRequests(List<CaptureRequest> requests) { 385 if (requests == null) { 386 throw new IllegalArgumentException("requests must not be null"); 387 } else if (requests.isEmpty()) { 388 throw new IllegalArgumentException("requests must have at least one element"); 389 } 390 391 for (CaptureRequest r : requests) { 392 if (r.isReprocess()) { 393 throw new IllegalArgumentException("repeating reprocess burst requests are not " + 394 "supported"); 395 } 396 } 397 } 398 399 @Override stopRepeating()400 public void stopRepeating() throws CameraAccessException { 401 synchronized (mDeviceImpl.mInterfaceLock) { 402 checkNotClosed(); 403 404 if (DEBUG) { 405 Log.v(TAG, mIdString + "stopRepeating"); 406 } 407 408 mDeviceImpl.stopRepeating(); 409 } 410 } 411 412 @Override abortCaptures()413 public void abortCaptures() throws CameraAccessException { 414 synchronized (mDeviceImpl.mInterfaceLock) { 415 checkNotClosed(); 416 417 if (DEBUG) { 418 Log.v(TAG, mIdString + "abortCaptures"); 419 } 420 421 if (mAborting) { 422 Log.w(TAG, mIdString + "abortCaptures - Session is already aborting; doing nothing"); 423 return; 424 } 425 426 mAborting = true; 427 mAbortDrainer.taskStarted(); 428 429 mDeviceImpl.flush(); 430 // The next BUSY -> IDLE set of transitions will mark the end of the abort. 431 } 432 } 433 434 @Override updateOutputConfiguration(OutputConfiguration config)435 public void updateOutputConfiguration(OutputConfiguration config) 436 throws CameraAccessException { 437 synchronized (mDeviceImpl.mInterfaceLock) { 438 checkNotClosed(); 439 440 if (DEBUG) { 441 Log.v(TAG, mIdString + "updateOutputConfiguration"); 442 } 443 444 mDeviceImpl.updateOutputConfiguration(config); 445 } 446 } 447 448 @Override isReprocessable()449 public boolean isReprocessable() { 450 return mInput != null; 451 } 452 453 @Override getInputSurface()454 public Surface getInputSurface() { 455 return mInput; 456 } 457 458 /** 459 * Replace this session with another session. 460 * 461 * <p>This is an optimization to avoid unconfiguring and then immediately having to 462 * reconfigure again.</p> 463 * 464 * <p>The semantics are identical to {@link #close}, except that unconfiguring will be skipped. 465 * <p> 466 * 467 * <p>After this call completes, the session will not call any further methods on the camera 468 * device.</p> 469 * 470 * @see CameraCaptureSession#close 471 */ 472 @Override replaceSessionClose()473 public void replaceSessionClose() { 474 synchronized (mDeviceImpl.mInterfaceLock) { 475 /* 476 * In order for creating new sessions to be fast, the new session should be created 477 * before the old session is closed. 478 * 479 * Otherwise the old session will always unconfigure if there is no new session to 480 * replace it. 481 * 482 * Unconfiguring could add hundreds of milliseconds of delay. We could race and attempt 483 * to skip unconfigure if a new session is created before the captures are all drained, 484 * but this would introduce nondeterministic behavior. 485 */ 486 487 if (DEBUG) Log.v(TAG, mIdString + "replaceSessionClose"); 488 489 // Set up fast shutdown. Possible alternative paths: 490 // - This session is active, so close() below starts the shutdown drain 491 // - This session is mid-shutdown drain, and hasn't yet reached the idle drain listener. 492 // - This session is already closed and has executed the idle drain listener, and 493 // configureOutputsChecked(null) has already been called. 494 // 495 // Do not call configureOutputsChecked(null) going forward, since it would race with the 496 // configuration for the new session. If it was already called, then we don't care, 497 // since it won't get called again. 498 mSkipUnconfigure = true; 499 close(); 500 } 501 } 502 503 @Override close()504 public void close() { 505 synchronized (mDeviceImpl.mInterfaceLock) { 506 if (mClosed) { 507 if (DEBUG) Log.v(TAG, mIdString + "close - reentering"); 508 return; 509 } 510 511 if (DEBUG) Log.v(TAG, mIdString + "close - first time"); 512 513 mClosed = true; 514 515 /* 516 * Flush out any repeating request. Since camera is closed, no new requests 517 * can be queued, and eventually the entire request queue will be drained. 518 * 519 * If the camera device was already closed, short circuit and do nothing; since 520 * no more internal device callbacks will fire anyway. 521 * 522 * Otherwise, once stopRepeating is done, wait for camera to idle, then unconfigure 523 * the camera. Once that's done, fire #onClosed. 524 */ 525 try { 526 mDeviceImpl.stopRepeating(); 527 } catch (IllegalStateException e) { 528 // OK: Camera device may already be closed, nothing else to do 529 530 // TODO: Fire onClosed anytime we get the device onClosed or the ISE? 531 // or just suppress the ISE only and rely onClosed. 532 // Also skip any of the draining work if this is already closed. 533 534 // Short-circuit; queue callback immediately and return 535 mStateCallback.onClosed(this); 536 return; 537 } catch (CameraAccessException e) { 538 // OK: close does not throw checked exceptions. 539 Log.e(TAG, mIdString + "Exception while stopping repeating: ", e); 540 541 // TODO: call onError instead of onClosed if this happens 542 } 543 544 // If no sequences are pending, fire #onClosed immediately 545 mSequenceDrainer.beginDrain(); 546 } 547 if (mInput != null) { 548 mInput.release(); 549 } 550 } 551 552 /** 553 * Whether currently in mid-abort. 554 * 555 * <p>This is used by the implementation to set the capture failure 556 * reason, in lieu of more accurate error codes from the camera service. 557 * Unsynchronized to avoid deadlocks between simultaneous session->device, 558 * device->session calls.</p> 559 * 560 */ 561 @Override isAborting()562 public boolean isAborting() { 563 return mAborting; 564 } 565 566 /** 567 * Post calls into a CameraCaptureSession.StateCallback to the user-specified {@code executor}. 568 */ createUserStateCallbackProxy(Executor executor, StateCallback callback)569 private StateCallback createUserStateCallbackProxy(Executor executor, StateCallback callback) { 570 return new CallbackProxies.SessionStateCallbackProxy(executor, callback); 571 } 572 573 /** 574 * Forward callbacks from 575 * CameraDeviceImpl.CaptureCallback to the CameraCaptureSession.CaptureCallback. 576 * 577 * <p>When a capture sequence finishes, update the pending checked sequences set.</p> 578 */ 579 @SuppressWarnings("deprecation") createCaptureCallbackProxy( Handler handler, CaptureCallback callback)580 private CameraDeviceImpl.CaptureCallback createCaptureCallbackProxy( 581 Handler handler, CaptureCallback callback) { 582 final Executor executor = (callback != null) ? CameraDeviceImpl.checkAndWrapHandler( 583 handler) : null; 584 585 return createCaptureCallbackProxyWithExecutor(executor, callback); 586 } 587 createCaptureCallbackProxyWithExecutor( Executor executor, CaptureCallback callback)588 private CameraDeviceImpl.CaptureCallback createCaptureCallbackProxyWithExecutor( 589 Executor executor, CaptureCallback callback) { 590 return new CameraDeviceImpl.CaptureCallback() { 591 @Override 592 public void onCaptureStarted(CameraDevice camera, 593 CaptureRequest request, long timestamp, long frameNumber) { 594 if ((callback != null) && (executor != null)) { 595 final long ident = Binder.clearCallingIdentity(); 596 try { 597 executor.execute(() -> callback.onCaptureStarted( 598 CameraCaptureSessionImpl.this, request, timestamp, 599 frameNumber)); 600 } finally { 601 Binder.restoreCallingIdentity(ident); 602 } 603 } 604 } 605 606 @Override 607 public void onCapturePartial(CameraDevice camera, 608 CaptureRequest request, android.hardware.camera2.CaptureResult result) { 609 if ((callback != null) && (executor != null)) { 610 final long ident = Binder.clearCallingIdentity(); 611 try { 612 executor.execute(() -> callback.onCapturePartial( 613 CameraCaptureSessionImpl.this, request, result)); 614 } finally { 615 Binder.restoreCallingIdentity(ident); 616 } 617 } 618 } 619 620 @Override 621 public void onCaptureProgressed(CameraDevice camera, 622 CaptureRequest request, android.hardware.camera2.CaptureResult partialResult) { 623 if ((callback != null) && (executor != null)) { 624 final long ident = Binder.clearCallingIdentity(); 625 try { 626 executor.execute(() -> callback.onCaptureProgressed( 627 CameraCaptureSessionImpl.this, request, partialResult)); 628 } finally { 629 Binder.restoreCallingIdentity(ident); 630 } 631 } 632 } 633 634 @Override 635 public void onCaptureCompleted(CameraDevice camera, 636 CaptureRequest request, android.hardware.camera2.TotalCaptureResult result) { 637 if ((callback != null) && (executor != null)) { 638 final long ident = Binder.clearCallingIdentity(); 639 try { 640 executor.execute(() -> callback.onCaptureCompleted( 641 CameraCaptureSessionImpl.this, request, result)); 642 } finally { 643 Binder.restoreCallingIdentity(ident); 644 } 645 } 646 } 647 648 @Override 649 public void onCaptureFailed(CameraDevice camera, 650 CaptureRequest request, android.hardware.camera2.CaptureFailure failure) { 651 if ((callback != null) && (executor != null)) { 652 final long ident = Binder.clearCallingIdentity(); 653 try { 654 executor.execute(() -> callback.onCaptureFailed( 655 CameraCaptureSessionImpl.this, request, failure)); 656 } finally { 657 Binder.restoreCallingIdentity(ident); 658 } 659 } 660 } 661 662 @Override 663 public void onCaptureSequenceCompleted(CameraDevice camera, 664 int sequenceId, long frameNumber) { 665 if ((callback != null) && (executor != null)) { 666 final long ident = Binder.clearCallingIdentity(); 667 try { 668 executor.execute(() -> callback.onCaptureSequenceCompleted( 669 CameraCaptureSessionImpl.this, sequenceId, frameNumber)); 670 } finally { 671 Binder.restoreCallingIdentity(ident); 672 } 673 } 674 finishPendingSequence(sequenceId); 675 } 676 677 @Override 678 public void onCaptureSequenceAborted(CameraDevice camera, 679 int sequenceId) { 680 if ((callback != null) && (executor != null)) { 681 final long ident = Binder.clearCallingIdentity(); 682 try { 683 executor.execute(() -> callback.onCaptureSequenceAborted( 684 CameraCaptureSessionImpl.this, sequenceId)); 685 } finally { 686 Binder.restoreCallingIdentity(ident); 687 } 688 } 689 finishPendingSequence(sequenceId); 690 } 691 692 @Override 693 public void onCaptureBufferLost(CameraDevice camera, 694 CaptureRequest request, Surface target, long frameNumber) { 695 if ((callback != null) && (executor != null)) { 696 final long ident = Binder.clearCallingIdentity(); 697 try { 698 executor.execute(() -> callback.onCaptureBufferLost( 699 CameraCaptureSessionImpl.this, request, target, frameNumber)); 700 } finally { 701 Binder.restoreCallingIdentity(ident); 702 } 703 } 704 } 705 }; 706 } 707 708 /** 709 * 710 * Create an internal state callback, to be invoked on the mDeviceExecutor 711 * 712 * <p>It has a few behaviors: 713 * <ul> 714 * <li>Convert device state changes into session state changes. 715 * <li>Keep track of async tasks that the session began (idle, abort). 716 * </ul> 717 * </p> 718 * */ 719 @Override 720 public CameraDeviceImpl.StateCallbackKK getDeviceStateCallback() { 721 final CameraCaptureSession session = this; 722 final Object interfaceLock = mDeviceImpl.mInterfaceLock; 723 724 725 return new CameraDeviceImpl.StateCallbackKK() { 726 private boolean mBusy = false; 727 private boolean mActive = false; 728 729 @Override 730 public void onOpened(CameraDevice camera) { 731 throw new AssertionError("Camera must already be open before creating a session"); 732 } 733 734 @Override 735 public void onDisconnected(CameraDevice camera) { 736 if (DEBUG) Log.v(TAG, mIdString + "onDisconnected"); 737 close(); 738 } 739 740 @Override 741 public void onError(CameraDevice camera, int error) { 742 // Should not be reached, handled by device code 743 Log.wtf(TAG, mIdString + "Got device error " + error); 744 } 745 746 @Override 747 public void onActive(CameraDevice camera) { 748 mIdleDrainer.taskStarted(); 749 mActive = true; 750 751 if (DEBUG) Log.v(TAG, mIdString + "onActive"); 752 mStateCallback.onActive(session); 753 } 754 755 @Override 756 public void onIdle(CameraDevice camera) { 757 boolean isAborting; 758 if (DEBUG) Log.v(TAG, mIdString + "onIdle"); 759 760 synchronized (interfaceLock) { 761 isAborting = mAborting; 762 } 763 764 /* 765 * Check which states we transitioned through: 766 * 767 * (ACTIVE -> IDLE) 768 * (BUSY -> IDLE) 769 * 770 * Note that this is also legal: 771 * (ACTIVE -> BUSY -> IDLE) 772 * 773 * and mark those tasks as finished 774 */ 775 if (mBusy && isAborting) { 776 mAbortDrainer.taskFinished(); 777 778 synchronized (interfaceLock) { 779 mAborting = false; 780 } 781 } 782 783 if (mActive) { 784 mIdleDrainer.taskFinished(); 785 } 786 787 mBusy = false; 788 mActive = false; 789 790 mStateCallback.onReady(session); 791 } 792 793 @Override 794 public void onBusy(CameraDevice camera) { 795 mBusy = true; 796 797 // TODO: Queue captures during abort instead of failing them 798 // since the app won't be able to distinguish the two actives 799 // Don't signal the application since there's no clean mapping here 800 if (DEBUG) Log.v(TAG, mIdString + "onBusy"); 801 } 802 803 @Override 804 public void onUnconfigured(CameraDevice camera) { 805 if (DEBUG) Log.v(TAG, mIdString + "onUnconfigured"); 806 } 807 808 @Override 809 public void onRequestQueueEmpty() { 810 if (DEBUG) Log.v(TAG, mIdString + "onRequestQueueEmpty"); 811 mStateCallback.onCaptureQueueEmpty(session); 812 } 813 814 @Override 815 public void onSurfacePrepared(Surface surface) { 816 if (DEBUG) Log.v(TAG, mIdString + "onSurfacePrepared"); 817 mStateCallback.onSurfacePrepared(session, surface); 818 } 819 }; 820 821 } 822 823 @Override 824 protected void finalize() throws Throwable { 825 try { 826 close(); 827 } finally { 828 super.finalize(); 829 } 830 } 831 832 private void checkNotClosed() { 833 if (mClosed) { 834 throw new IllegalStateException( 835 "Session has been closed; further changes are illegal."); 836 } 837 } 838 839 /** 840 * Notify the session that a pending capture sequence has just been queued. 841 * 842 * <p>During a shutdown/close, the session waits until all pending sessions are finished 843 * before taking any further steps to shut down itself.</p> 844 * 845 * @see #finishPendingSequence 846 */ 847 private int addPendingSequence(int sequenceId) { 848 mSequenceDrainer.taskStarted(sequenceId); 849 return sequenceId; 850 } 851 852 /** 853 * Notify the session that a pending capture sequence is now finished. 854 * 855 * <p>During a shutdown/close, once all pending sequences finish, it is safe to 856 * close the camera further by unconfiguring and then firing {@code onClosed}.</p> 857 */ 858 private void finishPendingSequence(int sequenceId) { 859 try { 860 mSequenceDrainer.taskFinished(sequenceId); 861 } catch (IllegalStateException e) { 862 // Workaround for b/27870771 863 Log.w(TAG, e.getMessage()); 864 } 865 } 866 867 private class SequenceDrainListener implements TaskDrainer.DrainListener { 868 @Override 869 public void onDrained() { 870 /* 871 * No repeating request is set; and the capture queue has fully drained. 872 * 873 * If no captures were queued to begin with, and an abort was queued, 874 * it's still possible to get another BUSY before the last IDLE. 875 * 876 * If the camera is already "IDLE" and no aborts are pending, 877 * then the drain immediately finishes. 878 */ 879 if (DEBUG) Log.v(TAG, mIdString + "onSequenceDrained"); 880 881 882 // Fire session close as soon as all sequences are complete. 883 // We may still need to unconfigure the device, but a new session might be created 884 // past this point, and notifications would then stop to this instance. 885 mStateCallback.onClosed(CameraCaptureSessionImpl.this); 886 887 // Fast path: A new capture session has replaced this one; don't wait for abort/idle 888 // as we won't get state updates any more anyway. 889 if (mSkipUnconfigure) { 890 return; 891 } 892 893 mAbortDrainer.beginDrain(); 894 } 895 } 896 897 private class AbortDrainListener implements TaskDrainer.DrainListener { 898 @Override 899 public void onDrained() { 900 if (DEBUG) Log.v(TAG, mIdString + "onAbortDrained"); 901 synchronized (mDeviceImpl.mInterfaceLock) { 902 /* 903 * Any queued aborts have now completed. 904 * 905 * It's now safe to wait to receive the final "IDLE" event, as the camera device 906 * will no longer again transition to "ACTIVE" by itself. 907 * 908 * If the camera is already "IDLE", then the drain immediately finishes. 909 */ 910 911 // Fast path: A new capture session has replaced this one; don't wait for idle 912 // as we won't get state updates any more anyway. 913 if (mSkipUnconfigure) { 914 return; 915 } 916 mIdleDrainer.beginDrain(); 917 } 918 } 919 } 920 921 private class IdleDrainListener implements TaskDrainer.DrainListener { 922 @Override 923 public void onDrained() { 924 if (DEBUG) Log.v(TAG, mIdString + "onIdleDrained"); 925 926 // Take device lock before session lock so that we can call back into device 927 // without causing a deadlock 928 synchronized (mDeviceImpl.mInterfaceLock) { 929 /* 930 * The device is now IDLE, and has settled. It will not transition to 931 * ACTIVE or BUSY again by itself. 932 * 933 * It's now safe to unconfigure the outputs. 934 * 935 * This operation is idempotent; a session will not be closed twice. 936 */ 937 if (DEBUG) 938 Log.v(TAG, mIdString + "Session drain complete, skip unconfigure: " + 939 mSkipUnconfigure); 940 941 // Fast path: A new capture session has replaced this one; don't wait for idle 942 // as we won't get state updates any more anyway. 943 if (mSkipUnconfigure) { 944 return; 945 } 946 947 // Final slow path: unconfigure the camera, no session has replaced us and 948 // everything is idle. 949 try { 950 // begin transition to unconfigured 951 mDeviceImpl.configureStreamsChecked(/*inputConfig*/null, /*outputs*/null, 952 /*operatingMode*/ ICameraDeviceUser.NORMAL_MODE, 953 /*sessionParams*/ null); 954 } catch (CameraAccessException e) { 955 // OK: do not throw checked exceptions. 956 Log.e(TAG, mIdString + "Exception while unconfiguring outputs: ", e); 957 958 // TODO: call onError instead of onClosed if this happens 959 } catch (IllegalStateException e) { 960 // Camera is already closed, so nothing left to do 961 if (DEBUG) Log.v(TAG, mIdString + 962 "Camera was already closed or busy, skipping unconfigure"); 963 } 964 } 965 } 966 } 967 968 } 969