Search code examples
androidandroid-mediarecorderandroid-mediaprojection

MediaRecorder not recording the second time


I am using MediaRecorder to record the user screen. Everything is working fine when the app is opened for the first time and the user clicks the fab button to record the screen. But if the app is running, the user clicks the record button again, no new file is generated in my desired filepath and so my listview isn't updated.

If I close the app and run the app again, it mediarecorder only works the first time only. I have tried many different ways and looked for solutions all over Stack Overflow but it was all in vain. I just can't record the screen the second time the record button is clicked. I also do not get any errors. Here is my code:

public class MainActivity extends AppCompatActivity {

private static final String TAG = "MainActivity";
private static final int DISPLAY_WIDTH = 720;
private static final int DISPLAY_HEIGHT = 1280;
Button btn;
private int screenDensity;
private MediaProjectionManager mediaProjectionManager;
private MediaProjection mediaProjection;
private VirtualDisplay virtualDisplay;
private MediaProjection.Callback mediaProjectionCallback;
private MediaRecorder mediaRecorder;
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private boolean isRecording = false;
static SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy hh:mm:ss");
static String todayDate = dateFormat.format(new Date());

static {
    ORIENTATIONS.append(Surface.ROTATION_0, 90);
    ORIENTATIONS.append(Surface.ROTATION_90, 0);
    ORIENTATIONS.append(Surface.ROTATION_180, 270);
    ORIENTATIONS.append(Surface.ROTATION_270, 180);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    String[] PERMISSIONS = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO};

    if (!hasPermissions(this, PERMISSIONS)) {
        ActivityCompat.requestPermissions(this, PERMISSIONS, 1);
    }

    DisplayMetrics displayMetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
    screenDensity = displayMetrics.densityDpi;

    mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);

    btn = findViewById(R.id.fab);
    btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            toggleScreenShare();
        }
    });
}

public static boolean hasPermissions(Context context, String... permissions) {
    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) {
        for (String permission : permissions) {
            if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
    }
    return true;
}

public void recordBtnReload() {
    if (isRecording) {
        btn.setText("Stop");
    } else {
        btn.setText("Record");
    }
}

private void toggleScreenShare() {
    if (!isRecording) {
        initRecorder();
        shareScreen();
    } else {
        mediaRecorder.stop();
        mediaRecorder.reset();
        mediaRecorder.release();
        mediaRecorder = null;
        stopScreenSharing();
    }
}

private void stopScreenSharing() {
    if (virtualDisplay == null) {
        return;
    }
    virtualDisplay.release();
    destroyMediaProjection();
    isRecording = false;
    recordBtnReload();
}

private void destroyMediaProjection() {
    if (mediaProjection != null) {
        mediaProjection.unregisterCallback(mediaProjectionCallback);
        mediaProjection.stop();
        mediaProjection = null;
    }
    Log.i(TAG, "MediaProjection is stopped for now");
}

private void shareScreen() {
    if (mediaProjection == null) {
        startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), 1000);
        return;
    }
    virtualDisplay = createVirtualDisplay();
    mediaRecorder.start();
    isRecording = true;
    recordBtnReload();
    Log.i(TAG, "ShareScreen started for now");
}

private void initRecorder() {
    try {
        mediaRecorder = new MediaRecorder();
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

        mediaRecorder.setVideoSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        mediaRecorder.setVideoEncodingBitRate(512 * 1000);
        mediaRecorder.setVideoFrameRate(16);
        mediaRecorder.setVideoEncodingBitRate(3000000);
        String directory = Environment.getExternalStorageDirectory() + File.separator + "NewCapture";
        File folder = new File(directory);
        boolean success = true;
        if (!folder.exists()) {
            success = folder.mkdir();
        }
        String filepath;
        if (success) {
            String videoName = ("Video_" + todayDate + ".mp4");
            filepath = directory + File.separator + videoName;
            Log.i(TAG, "File created");
        } else {
            Toast.makeText(this, "Failed to create Recordings directory", Toast.LENGTH_SHORT).show();
            return;
        }
        mediaRecorder.setOutputFile(filepath);
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        int orientation = ORIENTATIONS.get(rotation + 90);
        mediaRecorder.setOrientationHint(orientation);
        mediaRecorder.prepare();
        Log.i(TAG, "initRecorder");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private VirtualDisplay createVirtualDisplay() {
    Log.i(TAG, "Created Virtual Display");
    return mediaProjection.createVirtualDisplay(TAG, DISPLAY_WIDTH, DISPLAY_HEIGHT, screenDensity,
            DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mediaRecorder.getSurface(), null, null);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode != 1000) {
        Log.e(TAG, "Unknown request code:" + requestCode);
        return;
    }
    if (resultCode != RESULT_OK) {
        Toast.makeText(this, "Permission for screen recording is denied", Toast.LENGTH_LONG).show();
        isRecording = false;
        recordBtnReload();
        return;
    }
    mediaProjectionCallback = new MediaProjection.Callback() {
        @Override
        public void onStop() {
            if (isRecording) {
                isRecording = false;
                recordBtnReload();
                mediaRecorder.stop();
                mediaRecorder.reset();
                mediaRecorder.release();
                mediaRecorder = null;
            }
            mediaProjection = null;
            stopScreenSharing();
        }
    };

    mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
    mediaProjection.registerCallback(mediaProjectionCallback, null);
    virtualDisplay = createVirtualDisplay();
    mediaRecorder.start();
    isRecording = true;
    recordBtnReload();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    destroyMediaProjection();
}

}

I have no idea what I am doing wrong. I am still learning app development.


Solution

  • The problem in my code was in the initRecorder() function. Instead of using the following code to create a filename:

    String videoName = ("Video_" + todayDate + ".mp4");
    

    Where, todayDate is a dateformatter. I replaced the code with the following:

    String videoName = ("Video_" + System.currentTimeMillis() + ".mp4");
    

    This takes the current system time and assigns it in the file name. Now new files are created and I don't have to re-launch the app again everytime to record new files.