mirror of
https://github.com/Myzel394/Alibi.git
synced 2025-06-18 23:05:26 +02:00
feat: Add lock / unlock method for interval files
Signed-off-by: Myzel394 <50424412+Myzel394@users.noreply.github.com>
This commit is contained in:
parent
671c8da56a
commit
6627289666
@ -3,28 +3,26 @@ package app.myzel394.alibi.helpers
|
||||
import android.Manifest
|
||||
import android.content.ContentUris
|
||||
import android.content.ContentValues
|
||||
import app.myzel394.alibi.ui.MEDIA_RECORDINGS_PREFIX
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.MediaStore
|
||||
import android.provider.MediaStore.Video.Media
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import java.io.File
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import com.arthenica.ffmpegkit.FFmpegKitConfig
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.net.toUri
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import app.myzel394.alibi.ui.MEDIA_RECORDINGS_PREFIX
|
||||
import app.myzel394.alibi.ui.RECORDER_INTERNAL_SELECTED_VALUE
|
||||
import app.myzel394.alibi.ui.RECORDER_MEDIA_SELECTED_VALUE
|
||||
import app.myzel394.alibi.ui.SUPPORTS_SCOPED_STORAGE
|
||||
import app.myzel394.alibi.ui.utils.PermissionHelper
|
||||
import com.arthenica.ffmpegkit.FFprobeKit
|
||||
import com.arthenica.ffmpegkit.FFmpegKitConfig
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import java.io.File
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import kotlin.reflect.KFunction4
|
||||
|
||||
abstract class BatchesFolder(
|
||||
@ -197,7 +195,6 @@ abstract class BatchesFolder(
|
||||
createNewFile()
|
||||
}
|
||||
|
||||
|
||||
fun checkIfOutputAlreadyExists(
|
||||
date: LocalDateTime,
|
||||
extension: String
|
||||
@ -388,12 +385,12 @@ abstract class BatchesFolder(
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteOldRecordings(earliestCounter: Long) {
|
||||
fun deleteRecordings(range: LongRange) {
|
||||
when (type) {
|
||||
BatchType.INTERNAL -> getInternalFolder().listFiles()?.forEach {
|
||||
val fileCounter = it.nameWithoutExtension.toIntOrNull() ?: return@forEach
|
||||
|
||||
if (fileCounter < earliestCounter) {
|
||||
if (fileCounter in range) {
|
||||
it.delete()
|
||||
}
|
||||
}
|
||||
@ -401,7 +398,7 @@ abstract class BatchesFolder(
|
||||
BatchType.CUSTOM -> getCustomDefinedFolder().listFiles().forEach {
|
||||
val fileCounter = it.name?.substringBeforeLast(".")?.toIntOrNull() ?: return@forEach
|
||||
|
||||
if (fileCounter < earliestCounter) {
|
||||
if (fileCounter in range) {
|
||||
it.delete()
|
||||
}
|
||||
}
|
||||
@ -411,7 +408,7 @@ abstract class BatchesFolder(
|
||||
val deletableNames = mutableListOf<String>()
|
||||
|
||||
queryMediaContent { rawName, counter, _, _ ->
|
||||
if (counter < earliestCounter) {
|
||||
if (counter in range) {
|
||||
deletableNames.add(rawName)
|
||||
}
|
||||
}
|
||||
@ -428,7 +425,7 @@ abstract class BatchesFolder(
|
||||
it.nameWithoutExtension.substring(mediaPrefix.length).toIntOrNull()
|
||||
?: return@forEach
|
||||
|
||||
if (fileCounter < earliestCounter) {
|
||||
if (fileCounter in range) {
|
||||
it.delete()
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,9 @@ abstract class IntervalRecorderService<I, B : BatchesFolder> :
|
||||
protected var counter = 0L
|
||||
private set
|
||||
|
||||
// Tracks the index of the currently locked file
|
||||
private var lockedIndex: Long? = null
|
||||
|
||||
lateinit var settings: AppSettings
|
||||
|
||||
private lateinit var cycleTimer: ScheduledExecutorService
|
||||
@ -21,6 +24,23 @@ abstract class IntervalRecorderService<I, B : BatchesFolder> :
|
||||
|
||||
abstract fun getRecordingInformation(): I
|
||||
|
||||
// When saving the recording, the files should be locked.
|
||||
// This prevents the service from deleting the currently available files, so that
|
||||
// they can be safely used to save the recording.
|
||||
// Once finished, make sure to unlock the files using `unlockFiles`.
|
||||
fun lockFiles() {
|
||||
lockedIndex = counter
|
||||
}
|
||||
|
||||
// Unlocks and deletes the files that were locked using `lockFiles`.
|
||||
fun unlockFiles(cleanupFiles: Boolean = false) {
|
||||
if (cleanupFiles) {
|
||||
batchesFolder.deleteRecordings(0..lockedIndex!!)
|
||||
}
|
||||
|
||||
lockedIndex = null
|
||||
}
|
||||
|
||||
// Make overrideable
|
||||
open fun startNewCycle() {
|
||||
counter += 1
|
||||
@ -72,12 +92,12 @@ abstract class IntervalRecorderService<I, B : BatchesFolder> :
|
||||
|
||||
private fun deleteOldRecordings() {
|
||||
val timeMultiplier = settings.maxDuration / settings.intervalDuration
|
||||
val earliestCounter = counter - timeMultiplier
|
||||
val earliestCounter = Math.max(counter - timeMultiplier, lockedIndex ?: 0)
|
||||
|
||||
if (earliestCounter <= 0) {
|
||||
return
|
||||
}
|
||||
|
||||
batchesFolder.deleteOldRecordings(earliestCounter)
|
||||
batchesFolder.deleteRecordings(0..earliestCounter)
|
||||
}
|
||||
}
|
@ -139,7 +139,7 @@ class VideoRecorderService :
|
||||
if (_cameraAvailableListener.isCompleted) {
|
||||
action()
|
||||
} else {
|
||||
// Race condition of `startNewCycle` being called before `invpkeOnCompletion`
|
||||
// Race condition of `startNewCycle` being called before `invokeOnCompletion`
|
||||
// has been called can be ignored, as the camera usually opens within 5 seconds
|
||||
// and the interval can't be set shorter than 10 seconds.
|
||||
_cameraAvailableListener.invokeOnCompletion {
|
||||
|
@ -129,15 +129,17 @@ fun RecorderEventsHandler(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveRecording(recorder: RecorderModel) {
|
||||
suspend fun saveRecording(recorder: RecorderModel): Thread {
|
||||
isProcessing = true
|
||||
|
||||
// Give the user some time to see the processing dialog
|
||||
delay(100)
|
||||
|
||||
thread {
|
||||
return thread {
|
||||
runBlocking {
|
||||
try {
|
||||
recorder.recorderService?.lockFiles()
|
||||
|
||||
val recording =
|
||||
// When new recording created
|
||||
recorder.recorderService?.getRecordingInformation()
|
||||
@ -215,6 +217,7 @@ fun RecorderEventsHandler(
|
||||
} catch (error: Exception) {
|
||||
Log.getStackTraceString(error)
|
||||
} finally {
|
||||
recorder.recorderService?.unlockFiles()
|
||||
isProcessing = false
|
||||
}
|
||||
}
|
||||
@ -230,7 +233,7 @@ fun RecorderEventsHandler(
|
||||
// instead of hoping that the coroutine from where this will be called will be alive
|
||||
// until the end of the saving process
|
||||
scope.launch {
|
||||
saveRecording(audioRecorder as RecorderModel)
|
||||
saveRecording(audioRecorder as RecorderModel).join()
|
||||
}
|
||||
}
|
||||
audioRecorder.onRecordingStart = {
|
||||
@ -273,7 +276,7 @@ fun RecorderEventsHandler(
|
||||
// instead of hoping that the coroutine from where this will be called will be alive
|
||||
// until the end of the saving process
|
||||
scope.launch {
|
||||
saveRecording(videoRecorder as RecorderModel)
|
||||
saveRecording(videoRecorder as RecorderModel).join()
|
||||
}
|
||||
}
|
||||
videoRecorder.onRecordingStart = {
|
||||
|
@ -227,7 +227,7 @@ fun _PrimitiveControls(videoRecorder: VideoRecorderModel) {
|
||||
it.saveLastRecording(videoRecorder as RecorderModel)
|
||||
}
|
||||
|
||||
videoRecorder.onRecordingSave()
|
||||
videoRecorder.onRecordingSave().join()
|
||||
|
||||
runCatching {
|
||||
videoRecorder.destroyService(context)
|
||||
|
Loading…
x
Reference in New Issue
Block a user