mirror of
https://github.com/Myzel394/Alibi.git
synced 2025-06-18 23:05:26 +02:00
fix: Properly reset AudioRecorder
This commit is contained in:
parent
1269c6cb00
commit
9a43afbe3e
@ -11,9 +11,6 @@ import android.os.Handler
|
||||
import android.os.IBinder
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.core.app.NotificationCompat
|
||||
@ -35,7 +32,7 @@ import java.time.ZoneId
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.Date
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.UUID
|
||||
|
||||
const val AMPLITUDE_UPDATE_INTERVAL = 100L
|
||||
|
||||
@ -47,26 +44,20 @@ class RecorderService: Service() {
|
||||
|
||||
private var mediaRecorder: MediaRecorder? = null
|
||||
private var onError: MediaRecorder.OnErrorListener? = null
|
||||
private var onStateChange: (RecorderState) -> Unit = {}
|
||||
private var onAmplitudeUpdate: () -> Unit = {}
|
||||
|
||||
private var counter = 0
|
||||
|
||||
lateinit var settings: Settings
|
||||
|
||||
var recordingStart = mutableStateOf<LocalDateTime?>(null)
|
||||
private set
|
||||
var fileFolder: String? = null
|
||||
private set
|
||||
var recordingState: RecorderState = RecorderState.IDLE
|
||||
private set
|
||||
val isRecording: Boolean
|
||||
get() = recordingStart.value != null
|
||||
val isRecording = mutableStateOf(false)
|
||||
|
||||
val filePaths = mutableListOf<String>()
|
||||
val amplitudes = mutableStateListOf<Int>()
|
||||
|
||||
var originalRecordingStart: LocalDateTime? = null
|
||||
var recordingStart: LocalDateTime? = null
|
||||
private set
|
||||
|
||||
override fun onBind(p0: Intent?): IBinder = binder
|
||||
@ -90,21 +81,26 @@ class RecorderService: Service() {
|
||||
scope.cancel()
|
||||
}
|
||||
|
||||
fun setOnErrorListener(onError: MediaRecorder.OnErrorListener) {
|
||||
this.onError = onError
|
||||
}
|
||||
|
||||
fun setOnAmplitudeUpdateListener(onAmplitudeUpdate: () -> Unit) {
|
||||
this.onAmplitudeUpdate = onAmplitudeUpdate
|
||||
}
|
||||
|
||||
fun setOnStateChangeListener(onStateChange: (RecorderState) -> Unit) {
|
||||
this.onStateChange = onStateChange
|
||||
fun reset() {
|
||||
recordingStart = null
|
||||
counter = 0
|
||||
amplitudes.clear()
|
||||
isRecording.value = false
|
||||
|
||||
filePaths.forEach {
|
||||
File(it).delete()
|
||||
}
|
||||
|
||||
filePaths.clear()
|
||||
}
|
||||
|
||||
fun concatenateFiles(forceConcatenation: Boolean = false): File {
|
||||
val paths = filePaths.joinToString("|")
|
||||
val outputFile = "$fileFolder/${originalRecordingStart!!.format(DateTimeFormatter.ISO_DATE_TIME)}.${settings.fileExtension}"
|
||||
val outputFile = "$fileFolder/${recordingStart!!.format(DateTimeFormatter.ISO_DATE_TIME)}.${settings.fileExtension}"
|
||||
|
||||
if (File(outputFile).exists() && !forceConcatenation) {
|
||||
return File(outputFile)
|
||||
@ -132,7 +128,7 @@ class RecorderService: Service() {
|
||||
}
|
||||
|
||||
private fun updateAmplitude() {
|
||||
if (!isRecording || mediaRecorder == null) {
|
||||
if (!isRecording.value || mediaRecorder == null) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -144,7 +140,7 @@ class RecorderService: Service() {
|
||||
}
|
||||
|
||||
private fun startNewRecording() {
|
||||
if (!isRecording) {
|
||||
if (!isRecording.value) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -205,17 +201,15 @@ class RecorderService: Service() {
|
||||
|
||||
|
||||
private fun start() {
|
||||
amplitudes.clear()
|
||||
filePaths.clear()
|
||||
reset()
|
||||
// Create folder
|
||||
File(this.fileFolder!!).mkdirs()
|
||||
|
||||
scope.launch {
|
||||
dataStore.data.collectLatest { preferenceSettings ->
|
||||
settings = Settings.from(preferenceSettings.audioRecorderSettings)
|
||||
recordingState = RecorderState.RECORDING
|
||||
recordingStart.value = LocalDateTime.now()
|
||||
originalRecordingStart = recordingStart.value
|
||||
recordingStart = LocalDateTime.now()
|
||||
isRecording.value = true
|
||||
|
||||
showNotification()
|
||||
startNewRecording()
|
||||
@ -225,22 +219,20 @@ class RecorderService: Service() {
|
||||
}
|
||||
|
||||
private fun stop() {
|
||||
recordingState = RecorderState.IDLE
|
||||
|
||||
mediaRecorder?.apply {
|
||||
runCatching {
|
||||
stop()
|
||||
release()
|
||||
}
|
||||
}
|
||||
recordingStart.value = null
|
||||
isRecording.value = false
|
||||
|
||||
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
private fun showNotification() {
|
||||
if (recordingStart.value == null) {
|
||||
if (!isRecording.value) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -254,7 +246,7 @@ class RecorderService: Service() {
|
||||
.setOnlyAlertOnce(true)
|
||||
.setUsesChronometer(true)
|
||||
.setChronometerCountDown(false)
|
||||
.setWhen(Date.from(recordingStart.value!!.atZone(ZoneId.systemDefault()).toInstant()).time)
|
||||
.setWhen(Date.from(recordingStart!!.atZone(ZoneId.systemDefault()).toInstant()).time)
|
||||
.setShowWhen(true)
|
||||
.build()
|
||||
|
||||
@ -267,10 +259,10 @@ class RecorderService: Service() {
|
||||
|
||||
// To avoid int overflow, we'll use the number of seconds since 2023-01-01 01:01:01
|
||||
private fun getNotificationId(): Int {
|
||||
val offset = ZoneId.of("UTC").rules.getOffset(recordingStart.value)
|
||||
val offset = ZoneId.of("UTC").rules.getOffset(recordingStart!!)
|
||||
|
||||
return (
|
||||
recordingStart.value!!.toEpochSecond(offset) -
|
||||
recordingStart!!.toEpochSecond(offset) -
|
||||
LocalDateTime.of(2023, 1, 1, 1, 1).toEpochSecond(offset)
|
||||
).toInt()
|
||||
}
|
||||
@ -286,12 +278,6 @@ class RecorderService: Service() {
|
||||
STOP,
|
||||
}
|
||||
|
||||
enum class RecorderState {
|
||||
IDLE,
|
||||
RECORDING,
|
||||
PAUSED,
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getRandomFileFolder(context: Context): String {
|
||||
// uuid
|
||||
@ -302,7 +288,7 @@ class RecorderService: Service() {
|
||||
|
||||
fun startService(context: Context, connection: ServiceConnection?) {
|
||||
Intent(context, RecorderService::class.java).also { intent ->
|
||||
intent.action = RecorderService.Actions.START.toString()
|
||||
intent.action = Actions.START.toString()
|
||||
|
||||
ContextCompat.startForegroundService(context, intent)
|
||||
|
||||
@ -314,7 +300,7 @@ class RecorderService: Service() {
|
||||
|
||||
fun stopService(context: Context) {
|
||||
Intent(context, RecorderService::class.java).also { intent ->
|
||||
intent.action = RecorderService.Actions.STOP.toString()
|
||||
intent.action = Actions.STOP.toString()
|
||||
|
||||
context.startService(intent)
|
||||
}
|
||||
|
@ -15,7 +15,9 @@ import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Cancel
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Save
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
@ -55,7 +57,7 @@ fun RecordingStatus(
|
||||
|
||||
var now by remember { mutableStateOf(LocalDateTime.now()) }
|
||||
|
||||
val start = service.recordingStart.value!!
|
||||
val start = service.recordingStart!!
|
||||
val duration = now.toEpochSecond(ZoneId.systemDefault().rules.getOffset(now)) - start.toEpochSecond(ZoneId.systemDefault().rules.getOffset(start))
|
||||
val progress = duration / (service.settings.maxDuration / 1000f)
|
||||
|
||||
@ -81,7 +83,7 @@ fun RecordingStatus(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
val distance = Duration.between(service.recordingStart.value, now).toMillis()
|
||||
val distance = Duration.between(service.recordingStart, now).toMillis()
|
||||
|
||||
Pulsating {
|
||||
Box(
|
||||
@ -104,18 +106,81 @@ fun RecordingStatus(
|
||||
.width(300.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
|
||||
var showDeleteDialog by remember { mutableStateOf(false) }
|
||||
|
||||
if (showDeleteDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
showDeleteDialog = false
|
||||
},
|
||||
title = {
|
||||
Text("Delete Recording?")
|
||||
},
|
||||
text = {
|
||||
Text("Are you sure you want to delete this recording?")
|
||||
},
|
||||
icon = {
|
||||
Icon(
|
||||
Icons.Default.Delete,
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.semantics {
|
||||
contentDescription = "Confirm Recording Deletion"
|
||||
},
|
||||
onClick = {
|
||||
showDeleteDialog = false
|
||||
RecorderService.stopService(context)
|
||||
service.reset()
|
||||
},
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Delete,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(ButtonDefaults.IconSize),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
|
||||
Text("Delete")
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.semantics {
|
||||
contentDescription = "Cancel Recording Deletion"
|
||||
},
|
||||
onClick = {
|
||||
showDeleteDialog = false
|
||||
},
|
||||
colors = ButtonDefaults.textButtonColors(),
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Cancel,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(ButtonDefaults.IconSize),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
|
||||
Text("Cancel")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.semantics {
|
||||
contentDescription = "Delete Recording"
|
||||
},
|
||||
onClick = {
|
||||
RecorderService.stopService(context)
|
||||
showDeleteDialog = true
|
||||
},
|
||||
colors = ButtonDefaults.textButtonColors(),
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Cancel,
|
||||
Icons.Default.Delete,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(ButtonDefaults.IconSize),
|
||||
)
|
||||
|
@ -1,9 +1,7 @@
|
||||
package app.myzel394.locationtest.ui.components.AudioRecorder.atoms
|
||||
|
||||
import android.content.ServiceConnection
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@ -25,8 +23,6 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
@ -83,7 +79,7 @@ fun StartRecording(
|
||||
)
|
||||
}
|
||||
}
|
||||
if (service?.originalRecordingStart != null)
|
||||
if (service?.recordingStart != null)
|
||||
Column(
|
||||
modifier = Modifier.weight(1f),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
@ -112,7 +108,7 @@ fun StartRecording(
|
||||
.size(ButtonDefaults.IconSize),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
|
||||
Text("Save Recording from ${service.originalRecordingStart!!.format(DateTimeFormatter.ISO_DATE_TIME)}")
|
||||
Text("Save Recording from ${service.recordingStart!!.format(DateTimeFormatter.ISO_DATE_TIME)}")
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -58,9 +58,6 @@ fun AudioRecorder(
|
||||
object : ServiceConnection {
|
||||
override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
|
||||
service = (binder as RecorderService.LocalBinder).getService().also { service ->
|
||||
service.setOnStateChangeListener {
|
||||
println("asd")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +66,7 @@ fun AudioRecorder(
|
||||
}
|
||||
}
|
||||
|
||||
val isRecording = service?.isRecording ?: false
|
||||
val isRecording = service?.isRecording?.value ?: false
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
Intent(context, RecorderService::class.java).also { intent ->
|
||||
|
Loading…
x
Reference in New Issue
Block a user