Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Session has been closed; further changes are illegal

i was reading about many reports about this, but still couldn't find the answer for me. Sometimes, after capturing with camera2, an exception is throwing: java.lang.IllegalStateException: Session has been closed; further changes are illegal. I tried to check all the sessions not being null, when was doing something, but still get this. Any suggestion ? anything else should i handle?=, which i didn't ?

 private CameraCaptureSession.CaptureCallback mCaptureCallback
            = new CameraCaptureSession.CaptureCallback() {

        private void process(CaptureResult result) {
            switch (mState) {
                case STATE_PREVIEW: {

                    if(touchFocusEnabled) {
                        letSetCaptureSessionOnce = true;
                        mState = STATE_WAITING_LOCK;
                        try {
                            // Reset the auto-focus trigger
                            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                                    CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
                            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                                    CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE);

                            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
                                    mHandler);
                        } catch (CameraAccessException e) {
                            L.e("CameraLolipop --- CameraCaptureSession.CaptureCallback " + e);
                        }
                    } else {
                        if(letSetCaptureSessionOnce) {
                            try {
                                if ((null != mCaptureSession) && (isCameraOpen)) {
                                    mState = STATE_PREVIEW;
                                    mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
                                            mHandler);
                                    letSetCaptureSessionOnce = true;
                                }

                            } catch (CameraAccessException e) {
                                L.e("CameraLolipop --- CameraCaptureSession.CaptureCallback " + e);
                            }
                        }
                    }
                    break;
                }
                case STATE_WAITING_LOCK: {
                    if(touchFocusEnabled) {
                        mState = STATE_PICTURE_TAKEN;
                        touchFocusEnabled = false;

                        try {
                            if((mCaptureSession != null)  && (isCameraOpen)){
                                mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
                                        mHandler);
                            }
                        } catch (CameraAccessException e) {
                            L.e("CameraLolipop --- STATE_WAITING_LOCK " + e);
                        }

                        return;
                    }
                    Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
                    L.d("Focus state ", "STATE_WAITING_LOCK");
                    boolean fixedFocus = isFixedFocus();
                    if (afState == null) {
//                        if ((burstMode) && (getSupportedHardwareLevel() == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)) {
//                            captureStillPictureBurst();
//                        } else {
                            captureStillPicture();
//                        }
                    } else if ((CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
                            CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) || fixedFocus) {
                        L.d("Focus state ", "CONTROL_AF_STATE_FOCUSED_LOCKED or CONTROL_AF_STATE_NOT_FOCUSED_LOCKED");
                        // CONTROL_AE_STATE can be null on some devices
                        Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                        if (aeState == null ||
                                aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
                            mState = STATE_PICTURE_TAKEN;
                            if ((burstMode) && (getSupportedHardwareLevel() == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)) {
//                                captureStillPictureBurst();
                                captureStillPicture();
                            } else {
                                captureStillPicture();
                            }
                        } else {
                            runPrecaptureSequence();
                        }
                    }
                    break;
                }
                case STATE_WAITING_PRECAPTURE: {
                    L.d("Focus state ", "STATE_WAITING_PRECAPTURE");
                    // CONTROL_AE_STATE can be null on some devices
                    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                    if (aeState == null ||
                            aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
                            aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED || isFixedFocus()) {
                        mState = STATE_WAITING_NON_PRECAPTURE;
                    }

                    break;
                }
                case STATE_WAITING_NON_PRECAPTURE: {
                    L.d("Focus state ", "STATE_WAITING_NON_PRECAPTURE");
                    // CONTROL_AE_STATE can be null on some devices
                    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                    if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
                        mState = STATE_PICTURE_TAKEN;
                        if ((burstMode) && (getSupportedHardwareLevel() == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)) {
//                            captureStillPictureBurst();
                            captureStillPicture();
                        } else {
                            captureStillPicture();
                        }
                    }
                    break;
                }

                case STATE_PICTURE_TAKEN: {
                    Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
                    L.d("TOUCH", " afState " + afState);
                    mState = STATE_PREVIEW;
                    if(afState == 4) {
                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                    }

                    if(afState == 0) {
                            Handler handler = new Handler();
                            handler.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    mPreviewRequestBuilder
                                            .set(CaptureRequest.CONTROL_AF_REGIONS, null);
                                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                            CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE);

                                }
                            }, 2500);
                    }
                    break;
                }
            }
        }
@Override
        public void onCaptureProgressed(CameraCaptureSession session,
                                        CaptureRequest request,
                                        CaptureResult partialResult) {
            super.onCaptureProgressed(session, request, partialResult);
//            process(partialResult);
        }

        @Override
        public void onCaptureCompleted(CameraCaptureSession session,
                                       CaptureRequest request,
                                       TotalCaptureResult result) {
//            if ((mState != STATE_PREVIEW) || (touchFocusEnabled)) {
                super.onCaptureCompleted(session, request, result);
                if(session != null) {
                    process(result);
                }
        }
    };

and here is where session is being created:

 private CameraCaptureSession.StateCallback mSessionPreviewStateCallback = new CameraCaptureSession.StateCallback() {
    @Override
    public void onConfigured(CameraCaptureSession cameraCaptureSession) {
        L.i("Thread", "onConfigured---->" + Thread.currentThread().getName());
        // The camera is already closed
        if(null == mCameraDevice) {
            return;
        }
        try {
            mCaptureSession = cameraCaptureSession;
            mCameraSessionIsClosed = false;
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);

            if((isCameraOpen) && (mCaptureSession != null)){
                mPreviewRequest = mPreviewRequestBuilder.build();
                mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mHandler);
            }
            L.d("ex0003", "Test... mSessionPreviewStateCallback ");
        } catch (CameraAccessException e) {
            L.e("CameraLolipop --- openCamera() " + e);
        }
    }

    @Override
    public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
        Toast.makeText(getActivity(), "onConfigureFailed---Preview", Toast.LENGTH_SHORT).show();
    }
};

and in onPause closeCamera() is being called:

try {
        if(mCameraDevice == null && mCameraIsClosed) {
            return;
        }
        if((mCaptureSession != null) && (isCameraOpen)) {
            try {
                mCaptureSession.abortCaptures();
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
        mCameraOpenCloseLock.acquire();
        if (null != mCaptureSession) {
            mCaptureSession.close();
            mCaptureSession = null;
            mCameraSessionIsClosed = true;
        }
        if (null != mCameraDevice) {
            mCameraDevice.close();
            mCameraDevice = null;
            isCameraOpen = false;
            mCameraIsClosed = true;
        }
        if (null != mImageReader) {
            mImageReader.close();
            mImageReader = null;
        }
    } catch (InterruptedException e) {
        throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
    } finally {
        mCameraOpenCloseLock.release();
    }

and after stopBackgroundThread() and super.onPause() are being called.

like image 448
user0770 Avatar asked Oct 20 '16 05:10

user0770


3 Answers

In the documentation it says:

if this session is no longer active, either because the session was explicitly closed, a new session has been created or the camera device has been closed.

If you are using the camera2api sample-project, this means: You either call openCamera(), createCameraPreviewSession() or closeCamera() while another createCameraPreviewSession() was called aswell.

I solved this with a global variable, that is always set to true, when the function createCameraPreviewSession() is called; and is set to false, 10MS after createCameraPreviewSession() was finished. If this variable is true, I block all new createCameraPreviewSession() calls and also all closeCamera() calls.

This solution worked for me. However, I don't know if there is a fundamental reason, why you should not use this. If somebody knows better, please let me know.

like image 95
Felix Hegg Avatar answered Nov 07 '22 15:11

Felix Hegg


In my case problem was createCaptureRequest being called multiple when another is already in process(onConfigured/onConfigureFailed called).
What I end up was creating a boolean variable that keeps track if camera_preview is already in process, if so then do not make another createCaptureRequest.

like image 40
Zain Ali Avatar answered Nov 07 '22 16:11

Zain Ali


Check if all the camera configurations have been set with a flag, as @Rohit suggested or give some delay to the repeatingRequest of your mCaptureSession while it setting the configuration for you in parallel in the background. In my case I solved this exception by giving a delay of 500 mS to set the repeatingRequest like this:

new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                try {
                    mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(),
                            mCaptureCallback, null);
                } catch (CameraAccessException e) {
                    Log.e(TAG, "Failed to start camera preview because it couldn't access camera", e);
                } catch (IllegalStateException e) {
                    Log.e(TAG, "Failed to start camera preview.", e);
                }
            }
        }, 500);

Also, the same problem occurs when you first time grant permissions and initially start your camera preview(app crashes), but there you will get CameraAccessException stating "Failed to start camera session". In that case, you should give the same amount of delay while creating capture sessions like below:

void startCaptureSession() {
    if (!isCameraOpened() || !mPreview.isReady() || mImageReader == null) {
        return;
    }
    previewSize = chooseOptimalSize();
    mPreview.setBufferSize(previewSize.getWidth(), previewSize.getHeight());
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            try {
                Surface surface = mPreview.getSurface();
                mPreviewRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                mPreviewRequestBuilder.addTarget(surface);
                mCamera.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                        mSessionCallback, mBackgroundHandler);
            } catch (CameraAccessException e) {
                throw new RuntimeException("Failed to start camera session");
            }
        }
    }, 500);
}

I hope it helps.

like image 1
Jeet Singh Avatar answered Nov 07 '22 17:11

Jeet Singh