From d21580b0cb47106b9ad48f725cdae79ffe425d9b Mon Sep 17 00:00:00 2001
From: Myzel394 <50424412+Myzel394@users.noreply.github.com>
Date: Sun, 26 Nov 2023 14:12:31 +0100
Subject: [PATCH] chore: Improvements
---
app/src/main/AndroidManifest.xml | 2 +-
.../alibi/services/AudioRecorderService.kt | 94 ++++++++++++++++++-
.../ExtraRecorderInformationService.kt | 55 -----------
.../alibi/services/IntervalRecorderService.kt | 63 ++-----------
.../{VideoService.kt => OldVideoService.kt} | 28 ++----
.../alibi/services/RecorderService.kt | 8 +-
.../app/myzel394/alibi/ui/screens/POCVideo.kt | 13 ++-
7 files changed, 126 insertions(+), 137 deletions(-)
delete mode 100644 app/src/main/java/app/myzel394/alibi/services/ExtraRecorderInformationService.kt
rename app/src/main/java/app/myzel394/alibi/services/{VideoService.kt => OldVideoService.kt} (87%)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index dbaa892..2518136 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -52,7 +52,7 @@
android:name=".services.AudioRecorderService"
android:foregroundServiceType="microphone" />
diff --git a/app/src/main/java/app/myzel394/alibi/services/AudioRecorderService.kt b/app/src/main/java/app/myzel394/alibi/services/AudioRecorderService.kt
index 79d04fa..dcbcd2b 100644
--- a/app/src/main/java/app/myzel394/alibi/services/AudioRecorderService.kt
+++ b/app/src/main/java/app/myzel394/alibi/services/AudioRecorderService.kt
@@ -10,13 +10,17 @@ import android.net.Uri
import android.os.Build
import android.os.Handler
import android.os.Looper
+import androidx.compose.material3.SnackbarDuration
import androidx.documentfile.provider.DocumentFile
+import app.myzel394.alibi.db.AudioRecorderSettings
+import app.myzel394.alibi.db.RecordingInformation
import app.myzel394.alibi.enums.RecorderState
import app.myzel394.alibi.helpers.BatchesFolder
import app.myzel394.alibi.ui.utils.MicrophoneInfo
import java.lang.IllegalStateException
-class AudioRecorderService : IntervalRecorderService() {
+class AudioRecorderService :
+ IntervalRecorderService() {
var amplitudesAmount = 1000
var selectedMicrophone: MicrophoneInfo? = null
@@ -27,6 +31,37 @@ class AudioRecorderService : IntervalRecorderService() {
var onMicrophoneDisconnected: () -> Unit = {}
var onMicrophoneReconnected: () -> Unit = {}
+ var amplitudes = mutableListOf()
+ private set
+
+ private val handler = Handler(Looper.getMainLooper())
+
+ var onAmplitudeChange: ((List) -> Unit)? = null
+
+ private fun updateAmplitude() {
+ if (state !== RecorderState.RECORDING) {
+ return
+ }
+
+ amplitudes.add(getAmplitude())
+ onAmplitudeChange?.invoke(amplitudes)
+
+ // Delete old amplitudes
+ if (amplitudes.size > getAmplitudeAmount()) {
+ // Should be more efficient than dropping the elements, getting a new list
+ // clearing old list and adding new elements to it
+ repeat(amplitudes.size - getAmplitudeAmount()) {
+ amplitudes.removeAt(0)
+ }
+ }
+
+ handler.postDelayed(::updateAmplitude, 100)
+ }
+
+ private fun createAmplitudesTimer() {
+ handler.postDelayed(::updateAmplitude, 100)
+ }
+
/// Tell Android to use the correct bluetooth microphone, if any selected
private fun startAudioDevice() {
if (selectedMicrophone == null) {
@@ -102,6 +137,14 @@ class AudioRecorderService : IntervalRecorderService() {
}
}
+ override fun getRecordingInformation() = RecordingInformation(
+ folderPath = batchesFolder.exportFolderForSettings(),
+ recordingStart = recordingStart,
+ maxDuration = settings.maxDuration,
+ fileExtension = settings.fileExtension,
+ intervalDuration = settings.intervalDuration,
+ )
+
override fun startNewCycle() {
super.startNewCycle()
@@ -123,6 +166,7 @@ class AudioRecorderService : IntervalRecorderService() {
override fun start() {
super.start()
+ createAmplitudesTimer()
registerMicrophoneListener()
}
@@ -140,9 +184,14 @@ class AudioRecorderService : IntervalRecorderService() {
unregisterMicrophoneListener()
}
- override fun getAmplitudeAmount(): Int = amplitudesAmount
+ override fun resume() {
+ super.resume()
+ createAmplitudesTimer()
+ }
- override fun getAmplitude(): Int {
+ private fun getAmplitudeAmount(): Int = amplitudesAmount
+
+ private fun getAmplitude(): Int {
return try {
recorder!!.maxAmplitude
} catch (error: IllegalStateException) {
@@ -213,4 +262,43 @@ class AudioRecorderService : IntervalRecorderService() {
audioManager.unregisterAudioDeviceCallback(audioDeviceCallback)
}
+
+ data class Settings(
+ override val maxDuration: Long,
+ override val intervalDuration: Long,
+ val bitRate: Int,
+ val samplingRate: Int,
+ val outputFormat: Int,
+ val encoder: Int,
+ val folder: String? = null,
+ ) : IntervalRecorderService.Settings(
+ maxDuration = maxDuration,
+ intervalDuration = intervalDuration
+ ) {
+ val fileExtension: String
+ get() = when (outputFormat) {
+ MediaRecorder.OutputFormat.AAC_ADTS -> "aac"
+ MediaRecorder.OutputFormat.THREE_GPP -> "3gp"
+ MediaRecorder.OutputFormat.MPEG_4 -> "mp4"
+ MediaRecorder.OutputFormat.MPEG_2_TS -> "ts"
+ MediaRecorder.OutputFormat.WEBM -> "webm"
+ MediaRecorder.OutputFormat.AMR_NB -> "amr"
+ MediaRecorder.OutputFormat.AMR_WB -> "awb"
+ MediaRecorder.OutputFormat.OGG -> "ogg"
+ else -> "raw"
+ }
+
+ companion object {
+ fun from(audioRecorderSettings: AudioRecorderSettings): IntervalRecorderService.Settings {
+ return Settings(
+ intervalDuration = audioRecorderSettings.intervalDuration,
+ bitRate = audioRecorderSettings.bitRate,
+ samplingRate = audioRecorderSettings.getSamplingRate(),
+ outputFormat = audioRecorderSettings.getOutputFormat(),
+ encoder = audioRecorderSettings.getEncoder(),
+ maxDuration = audioRecorderSettings.maxDuration,
+ )
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/app/myzel394/alibi/services/ExtraRecorderInformationService.kt b/app/src/main/java/app/myzel394/alibi/services/ExtraRecorderInformationService.kt
deleted file mode 100644
index 013dc52..0000000
--- a/app/src/main/java/app/myzel394/alibi/services/ExtraRecorderInformationService.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-package app.myzel394.alibi.services
-
-import android.os.Handler
-import android.os.Looper
-import app.myzel394.alibi.enums.RecorderState
-import java.util.Timer
-import java.util.TimerTask
-import java.util.concurrent.Executors
-import java.util.concurrent.ScheduledExecutorService
-import java.util.concurrent.TimeUnit
-
-abstract class ExtraRecorderInformationService : RecorderService() {
- abstract fun getAmplitudeAmount(): Int
- abstract fun getAmplitude(): Int
-
- var amplitudes = mutableListOf()
- private set
-
- private val handler = Handler(Looper.getMainLooper())
-
- var onAmplitudeChange: ((List) -> Unit)? = null
-
- private fun updateAmplitude() {
- if (state !== RecorderState.RECORDING) {
- return
- }
-
- amplitudes.add(getAmplitude())
- onAmplitudeChange?.invoke(amplitudes)
-
- // Delete old amplitudes
- if (amplitudes.size > getAmplitudeAmount()) {
- // Should be more efficient than dropping the elements, getting a new list
- // clearing old list and adding new elements to it
- repeat(amplitudes.size - getAmplitudeAmount()) {
- amplitudes.removeAt(0)
- }
- }
-
- handler.postDelayed(::updateAmplitude, 100)
- }
-
- private fun createAmplitudesTimer() {
- handler.postDelayed(::updateAmplitude, 100)
- }
-
- override fun start() {
- createAmplitudesTimer()
- }
-
- override fun resume() {
- createAmplitudesTimer()
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/app/myzel394/alibi/services/IntervalRecorderService.kt b/app/src/main/java/app/myzel394/alibi/services/IntervalRecorderService.kt
index cc6ac55..8bcaede 100644
--- a/app/src/main/java/app/myzel394/alibi/services/IntervalRecorderService.kt
+++ b/app/src/main/java/app/myzel394/alibi/services/IntervalRecorderService.kt
@@ -19,14 +19,12 @@ import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
-abstract class IntervalRecorderService : ExtraRecorderInformationService() {
- private var job = SupervisorJob()
- private var scope = CoroutineScope(Dispatchers.IO + job)
-
+abstract class IntervalRecorderService :
+ RecorderService() {
protected var counter = 0L
private set
- lateinit var settings: Settings
+ lateinit var settings: S
private lateinit var cycleTimer: ScheduledExecutorService
@@ -34,13 +32,7 @@ abstract class IntervalRecorderService : ExtraRecorderInformationService() {
var onCustomOutputFolderNotAccessible: () -> Unit = {}
- fun getRecordingInformation(): RecordingInformation = RecordingInformation(
- folderPath = batchesFolder.exportFolderForSettings(),
- recordingStart = recordingStart,
- maxDuration = settings.maxDuration,
- fileExtension = settings.fileExtension,
- intervalDuration = settings.intervalDuration,
- )
+ abstract fun getRecordingInformation(): I
// Make overrideable
open fun startNewCycle() {
@@ -62,8 +54,6 @@ abstract class IntervalRecorderService : ExtraRecorderInformationService() {
}
override fun start() {
- super.start()
-
batchesFolder.initFolders()
if (!batchesFolder.checkIfFolderIsAccessible()) {
batchesFolder =
@@ -81,10 +71,6 @@ abstract class IntervalRecorderService : ExtraRecorderInformationService() {
override fun resume() {
createTimer()
-
- // We first want to start our timers, so the `ExtraRecorderInformationService` can fetch
- // amplitudes
- super.resume()
}
override fun stop() {
@@ -96,45 +82,14 @@ abstract class IntervalRecorderService : ExtraRecorderInformationService() {
}
private fun deleteOldRecordings() {
- val timeMultiplier = settings!!.maxDuration / settings!!.intervalDuration
+ val timeMultiplier = settings.maxDuration / settings.intervalDuration
val earliestCounter = counter - timeMultiplier
batchesFolder.deleteOldRecordings(earliestCounter)
}
- data class Settings(
- val maxDuration: Long,
- val intervalDuration: Long,
- val bitRate: Int,
- val samplingRate: Int,
- val outputFormat: Int,
- val encoder: Int,
- val folder: String? = null,
- ) {
- val fileExtension: String
- get() = when (outputFormat) {
- MediaRecorder.OutputFormat.AAC_ADTS -> "aac"
- MediaRecorder.OutputFormat.THREE_GPP -> "3gp"
- MediaRecorder.OutputFormat.MPEG_4 -> "mp4"
- MediaRecorder.OutputFormat.MPEG_2_TS -> "ts"
- MediaRecorder.OutputFormat.WEBM -> "webm"
- MediaRecorder.OutputFormat.AMR_NB -> "amr"
- MediaRecorder.OutputFormat.AMR_WB -> "awb"
- MediaRecorder.OutputFormat.OGG -> "ogg"
- else -> "raw"
- }
-
- companion object {
- fun from(audioRecorderSettings: AudioRecorderSettings): Settings {
- return Settings(
- intervalDuration = audioRecorderSettings.intervalDuration,
- bitRate = audioRecorderSettings.bitRate,
- samplingRate = audioRecorderSettings.getSamplingRate(),
- outputFormat = audioRecorderSettings.getOutputFormat(),
- encoder = audioRecorderSettings.getEncoder(),
- maxDuration = audioRecorderSettings.maxDuration,
- )
- }
- }
- }
+ abstract class Settings(
+ open val maxDuration: Long,
+ open val intervalDuration: Long,
+ )
}
\ No newline at end of file
diff --git a/app/src/main/java/app/myzel394/alibi/services/VideoService.kt b/app/src/main/java/app/myzel394/alibi/services/OldVideoService.kt
similarity index 87%
rename from app/src/main/java/app/myzel394/alibi/services/VideoService.kt
rename to app/src/main/java/app/myzel394/alibi/services/OldVideoService.kt
index c48e66d..2d109a9 100644
--- a/app/src/main/java/app/myzel394/alibi/services/VideoService.kt
+++ b/app/src/main/java/app/myzel394/alibi/services/OldVideoService.kt
@@ -3,26 +3,16 @@ package app.myzel394.alibi.services
import android.annotation.SuppressLint
import android.content.ContentValues
import android.content.pm.ServiceInfo
-import android.graphics.SurfaceTexture
-import android.hardware.Camera
import android.os.Build
import android.provider.MediaStore
-import android.view.Surface
-import android.view.TextureView
-import android.view.ViewGroup
-import androidx.camera.core.CameraProvider
import androidx.camera.core.CameraSelector
-import androidx.camera.core.Preview
-import androidx.camera.core.Preview.SurfaceProvider
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.MediaStoreOutputOptions
-import androidx.camera.video.PendingRecording
import androidx.camera.video.Quality
import androidx.camera.video.QualitySelector
import androidx.camera.video.Recorder
import androidx.camera.video.Recording
import androidx.camera.video.VideoCapture.withOutput
-import androidx.camera.video.VideoRecordEvent
import androidx.core.app.NotificationCompat
import androidx.core.app.ServiceCompat
import androidx.core.content.ContextCompat
@@ -31,13 +21,15 @@ import app.myzel394.alibi.NotificationHelper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
-class VideoService : LifecycleService() {
+
+class VideoService : IntervalRecorderService() {
+}
+
+class OldVideoService : LifecycleService() {
private var job = SupervisorJob()
private var scope = CoroutineScope(Dispatchers.IO + job)
@@ -88,7 +80,7 @@ class VideoService : LifecycleService() {
// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider = cameraProviderFuture.get()
val recorder = Recorder.Builder()
- .setQualitySelector(QualitySelector.from(Quality.HIGHEST))
+ .setQualitySelector(QualitySelector.from(Quality.LOWEST))
.build()
val videoCapture = withOutput(recorder)
// Select back camera as a default
@@ -98,7 +90,7 @@ class VideoService : LifecycleService() {
cameraProvider?.unbindAll()
// Bind use cases to camera
cameraProvider?.bindToLifecycle(
- this@VideoService,
+ this@OldVideoService,
cameraSelector,
videoCapture
)
@@ -108,7 +100,7 @@ class VideoService : LifecycleService() {
cycleTimer = Executors.newSingleThreadScheduledExecutor().also {
it.scheduleAtFixedRate(
{
- val mainHandler = ContextCompat.getMainExecutor(this@VideoService)
+ val mainHandler = ContextCompat.getMainExecutor(this@OldVideoService)
mainHandler.execute {
runCatching {
@@ -116,11 +108,11 @@ class VideoService : LifecycleService() {
}
val r =
- videoCapture.output.prepareRecording(this@VideoService, options)
+ videoCapture.output.prepareRecording(this@OldVideoService, options)
.withAudioEnabled()
recording =
- r.start(ContextCompat.getMainExecutor(this@VideoService), {})
+ r.start(ContextCompat.getMainExecutor(this@OldVideoService), {})
}
},
0,
diff --git a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt
index 02b5797..5648acb 100644
--- a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt
+++ b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt
@@ -10,6 +10,7 @@ import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.ServiceCompat
+import androidx.lifecycle.LifecycleService
import app.myzel394.alibi.NotificationHelper
import app.myzel394.alibi.enums.RecorderState
import app.myzel394.alibi.ui.utils.PermissionHelper
@@ -20,7 +21,7 @@ import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
-abstract class RecorderService : Service() {
+abstract class RecorderService : LifecycleService() {
private val binder = RecorderBinder()
private var isPaused: Boolean = false
@@ -44,7 +45,10 @@ abstract class RecorderService : Service() {
protected abstract fun resume()
protected abstract fun stop()
- override fun onBind(p0: Intent?): IBinder? = binder
+ override fun onBind(intent: Intent): IBinder? {
+ super.onBind(intent)
+ return binder
+ }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
when (intent?.action) {
diff --git a/app/src/main/java/app/myzel394/alibi/ui/screens/POCVideo.kt b/app/src/main/java/app/myzel394/alibi/ui/screens/POCVideo.kt
index a7cae21..fc42e09 100644
--- a/app/src/main/java/app/myzel394/alibi/ui/screens/POCVideo.kt
+++ b/app/src/main/java/app/myzel394/alibi/ui/screens/POCVideo.kt
@@ -3,22 +3,27 @@ package app.myzel394.alibi.ui.screens
import android.content.Intent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
-import app.myzel394.alibi.services.VideoService
+import app.myzel394.alibi.services.OldVideoService
@Composable
fun POCVideo() {
val context = LocalContext.current
- Box(modifier = Modifier.fillMaxSize()) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(64.dp)
+ ) {
Button(onClick = {
- val intent = Intent(context, VideoService::class.java)
+ val intent = Intent(context, OldVideoService::class.java)
ContextCompat.startForegroundService(context, intent)
}) {
Text("Start")