Trying to use Facebook Live api with my android app. I am using camera2 to pull up the camera on my live streaming activity but am getting this error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.hardware.camera2.CameraCaptureSession.abortCaptures()' on a null object reference
at com.example.mapdemo.StreamingActivity$4.onClick(StreamingActivity.java:151)
at android.view.View.performClick(View.java:6261)
at android.widget.TextView.performClick(TextView.java:11157)
at android.view.View$PerformClick.run(View.java:23748)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
I am not sure why this is an error. Here is the code around the line where the error is located...the line with the error begins with mCaptureCameraSession.abortCaptures():
package com.example.mapdemo;
import android.content.pm.PackageManager;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.NonNull;
import android.support.v13.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import com.facebook.AccessToken;
import com.facebook.GraphRequest;
import com.facebook.GraphResponse;
import com.facebook.HttpMethod;
import org.json.JSONException;
import java.util.ArrayList;
public class StreamingActivity extends AppCompatActivity implements SurfaceHolder.Callback2 {
private static final String TAG = "StreamingActivity";
private static final String[] REQUEST_PERMISSIONS = new String[]{
android.Manifest.permission.CAMERA,
android.Manifest.permission.RECORD_AUDIO,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private static final int REQUEST_CODE_CAMERA = 1;
private CameraManager mCameraManager;
private VideoEncoderCore mVideoEncoderCore;
private String mFrontCameraId, streamURL,name,surname;
private CameraDevice mCameraDevice;
private Handler mBackgroundHandler;
private HandlerThread mBackgroundThread;
private SurfaceView mSurfacView;
private Button buttonRecord;
private boolean isRecording = false;
private ArrayList<Surface> mSurfaces;
private CaptureRequest mCaptureRequestPreview;
private StreamModel streamModel;
private CaptureRequest mCaptureRequestRecord;
private CameraCaptureSession mCameraCaptureSession;
private CameraCaptureSession.StateCallback mCaptureSessionCallback = new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
mCameraCaptureSession = session;
try {
mCameraCaptureSession.setRepeatingRequest(
mCaptureRequestPreview,
new CameraCaptureSession.CaptureCallback() {},
mBackgroundHandler
);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
Log.d(TAG, "fafea") ;
}
};
private CameraDevice.StateCallback mCameraDeviceCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
mCameraDevice = camera;
// mCameraDevice.createCaptureSession();
//
// try {
// mCameraManager.setTorchMode(mFrontCameraId, true);
// } catch (CameraAccessException e) {
// e.printStackTrace();
// }
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
//@IntDef(value = {CameraDevice.StateCallback.ERROR_CAMERA_IN_USE, CameraDevice.StateCallback.ERROR_MAX_CAMERAS_IN_USE, CameraDevice.StateCallback.ERROR_CAMERA_DISABLED, CameraDevice.StateCallback.ERROR_CAMERA_DEVICE, CameraDevice.StateCallback.ERROR_CAMERA_SERVICE})
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_streaming);
mSurfacView = (SurfaceView) findViewById(R.id.surfaceView);
mSurfacView.getHolder().addCallback(StreamingActivity.this);
streamModel = new StreamModel();
/**
LoginManager.getInstance().logInWithPublishPermissions(
this,
Arrays.asList("publish_actions"));*/
new GraphRequest(
AccessToken.getCurrentAccessToken(), "/me/live_videos", null, HttpMethod.POST,
new GraphRequest.Callback() {
public void onCompleted(GraphResponse response) {
//Gson mGson = new Gson();
//streamModel=mGson.fromJson(response.toString(),StreamModel.class);
try {
streamURL=response.getJSONObject().get("stream_url").toString();
Log.e(TAG,response.getJSONObject().get("stream_url").toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
).executeAsync();
buttonRecord =(Button) findViewById(R.id.buttonRecord);
buttonRecord.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isRecording){
try {
mCameraCaptureSession.abortCaptures();
mCameraCaptureSession.setRepeatingRequest(
mCaptureRequestPreview,
new CameraCaptureSession.CaptureCallback() {},
mBackgroundHandler
);
} catch (CameraAccessException e) {
e.printStackTrace();
}
isRecording = false;
buttonRecord.setText("Play");
}
else{
isRecording = true;
try {
mCameraCaptureSession.abortCaptures();
mCameraCaptureSession.setRepeatingRequest(mCaptureRequestRecord, new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
mVideoEncoderCore.drainEncoder(false);
}
@Override
public void onCaptureSequenceAborted(@NonNull CameraCaptureSession session, int sequenceId) {
super.onCaptureSequenceAborted(session, sequenceId);
mVideoEncoderCore.drainEncoder(true);
}
}, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
buttonRecord.setText("Stop");
}
}
});
mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
try {
String[] cameraIds = mCameraManager.getCameraIdList();
if (cameraIds.length != 0) {
for (int i = 0; i < cameraIds.length; i++){
if (mCameraManager.getCameraCharacteristics(cameraIds[i]).get(CameraCharacteristics.LENS_FACING)
== CameraCharacteristics.LENS_FACING_FRONT){
mFrontCameraId = cameraIds[i];
}
}
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onPause() {
super.onPause();
if (mVideoEncoderCore != null) {
mVideoEncoderCore.release();
}
}
private void startBackgroundThread() {
mBackgroundThread = new HandlerThread("CameraBackground");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
private void openCamera(){
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, REQUEST_PERMISSIONS, REQUEST_CODE_CAMERA);
return;
}
try {
mCameraManager.openCamera(mFrontCameraId, mCameraDeviceCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { // there were 2 different types pf activity compats to import
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
try {
mCameraManager.openCamera(mFrontCameraId, mCameraDeviceCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void surfaceRedrawNeeded(SurfaceHolder holder) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
startBackgroundThread();
openCamera();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
/**
private String getVideoFilePath(Context context) {
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + "/"
+ System.currentTimeMillis() + ".mp4";
}
*/
/**
public void createCaptureSession(){
try {
mVideoEncoderCore = new VideoEncoderCore(
1280,
720,
4000000,
streamURL
);
Surface previewSurface = mSurfacView.getHolder().getSurface();
Surface encoderSurface = mVideoEncoderCore.getInputSurface();
CaptureRequest.Builder captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(previewSurface);
mSurfaces = new ArrayList<>();
mSurfaces.add(previewSurface);
mSurfaces.add(encoderSurface);
mCaptureRequestPreview = captureRequestBuilder.build();
captureRequestBuilder.addTarget(encoderSurface);
mCaptureRequestRecord = captureRequestBuilder.build();
mCameraDevice.createCaptureSession(mSurfaces, mCaptureSessionCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
*/
}
The Camera2 API has many asynchronous tasks associated with it - tasks that run in the background to complete some work, like opening the camera, closing the camera, getting focus etc.
These task use callbacks to report when they are complete.
In addition to this the activity or fragment itself may invoke other tasks in the background, which also use callbacks to communicate and which may interact with the camera also - for example the camera will typically be closed during activity or fragment pause events.
Managing all the callbacks can be tricky and race conditions can exist - you will find other Camera2 race condition questions and answers on Stackoverflow also.
In your case, the error is telling you that the captureSession object is null. The most likely reason for this is because it has been set to null, either by an out of sequence Callback due to a race condition, or because you inadvertently set it to null as part of your clean up before you were fully finished with it.