Skip to content

Instantly share code, notes, and snippets.

@Mercandj
Last active May 5, 2021 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Mercandj/43d49421fea691bc2554a92c551096b1 to your computer and use it in GitHub Desktop.
Save Mercandj/43d49421fea691bc2554a92c551096b1 to your computer and use it in GitHub Desktop.

Screen recorder - Android

  • Basic code to record screen on Android.
  • Record your app and other apps
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    intent ?: return super.onStartCommand(intent, flags, startId)
    val extras = intent.extras
        ?: return super.onStartCommand(intent, flags, startId)
    val action = extras.getString("action")
        ?: return super.onStartCommand(intent, flags, startId)
    when (action) {
        "start" -> {
            val resultCode = extras.getInt("result_code")
            fileOutputPath = extras.getString("file_output_path")!!
            val data = extras.getParcelable<Intent>("data")!!
            getAudioPcmFile().delete()
            getVideoNoSoundMp4File().delete()
            mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data)
            mediaProjection!!.registerCallback(mediaProjectionCallback, null)

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                val config =
                    AudioPlaybackCaptureConfiguration.Builder(mediaProjection!!)
                        .addMatchingUsage(AudioAttributes.USAGE_MEDIA)
                        .build()
                val audioFormat: AudioFormat = AudioFormat.Builder()
                    .setEncoding(audioFormat)
                    .setSampleRate(sampleRateInHz)
                    .setChannelMask(audioChannelConfig)
                    .build()
                audioRecord = AudioRecord.Builder()
                    .setAudioFormat(audioFormat)
                    .setBufferSizeInBytes(bufferSizeInBytes * audioNbChannels)
                    .setAudioPlaybackCaptureConfig(config)
                    .build()
                audioRecord!!.startRecording()
                audioRecordingThread = createAudioRecordingThread()
                audioRecordingThread!!.start()
            }
            mediaRecorder = createMediaRecorder(getVideoNoSoundMp4File())
            virtualDisplay = createVirtualDisplay(mediaRecorder!!)
            mediaRecorder!!.start()
        }
        "stop" -> {
            val wasRecording = isAudioRecording()
            virtualDisplay?.release()
            mediaProjection?.unregisterCallback(mediaProjectionCallback)
            mediaProjection?.stop()
            audioRecord?.stop()
            mediaRecorder?.stop()
            mediaRecorder?.reset()
            mediaRecorder = null
            virtualDisplay = null
            if (!wasRecording) {
                stopForeground(true)
                stopSelf()
            }
        }
    }
    return super.onStartCommand(intent, flags, startId)
}

private fun createVirtualDisplay(mediaRecorder: MediaRecorder): VirtualDisplay {
    val metrics = DisplayMetrics()
    ScreenRecordGraph.getWindowManager().defaultDisplay.getMetrics(metrics)
    return mediaProjection!!.createVirtualDisplay(
        "MainActivity",
        ScreenRecordGraph.DISPLAY_WIDTH,
        ScreenRecordGraph.DISPLAY_HEIGHT,
        metrics.densityDpi,
        DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
        mediaRecorder.surface,
        null,
        null
    )
}

private fun createMediaRecorder(outputFile: File): MediaRecorder {
    val mediaRecorder = MediaRecorder()
    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT)
    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE)
    mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
    mediaRecorder.setOutputFile(outputFile.absolutePath)
    mediaRecorder.setVideoSize(
        ScreenRecordGraph.DISPLAY_WIDTH,
        ScreenRecordGraph.DISPLAY_HEIGHT
    )
    mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264)
    mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
    mediaRecorder.setVideoEncodingBitRate(512 * 1_000)
    mediaRecorder.setVideoFrameRate(16) // 30
    mediaRecorder.setVideoEncodingBitRate(3_000_000)
    val rotation = windowManager.defaultDisplay.rotation
    val orientation = ORIENTATIONS.get(rotation + 90)
    mediaRecorder.setOrientationHint(orientation)
    mediaRecorder.prepare()
    return mediaRecorder
}

companion object {

    private val ORIENTATIONS = SparseIntArray()

    init {
        ORIENTATIONS.append(Surface.ROTATION_0, 90)
        ORIENTATIONS.append(Surface.ROTATION_90, 0)
        ORIENTATIONS.append(Surface.ROTATION_180, 270)
        ORIENTATIONS.append(Surface.ROTATION_270, 180)
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment