Skip to content

Commit

Permalink
feat: Add microphone selection
Browse files Browse the repository at this point in the history
  • Loading branch information
Myzel394 committed Oct 21, 2023
1 parent 862de21 commit df1d7ce
Show file tree
Hide file tree
Showing 9 changed files with 262 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import android.media.MediaRecorder
import android.media.MediaRecorder.OnErrorListener
import android.media.MediaRecorder.getAudioSourceMax
import android.os.Build
import app.myzel394.alibi.ui.utils.MicrophoneInfo
import java.lang.IllegalStateException

class AudioRecorderService: IntervalRecorderService() {
var amplitudesAmount = 1000
var selectedDevice: AudioDeviceInfo? = null
var selectedDevice: MicrophoneInfo? = null

var recorder: MediaRecorder? = null
private set
Expand All @@ -29,7 +30,7 @@ class AudioRecorderService: IntervalRecorderService() {
if (selectedDevice == null) {
audioManger.clearCommunicationDevice()
} else {
audioManger.setCommunicationDevice(selectedDevice!!)
audioManger.setCommunicationDevice(selectedDevice!!.deviceInfo)
}
} else {
if (selectedDevice == null) {
Expand Down Expand Up @@ -116,30 +117,4 @@ class AudioRecorderService: IntervalRecorderService() {
0
}
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent?.action == "changeAudioDevice") {
selectedDevice = intent.getStringExtra("deviceID")!!.let {
if (it == "null") {
null
} else {
val audioManager = getSystemService(AUDIO_SERVICE)!! as AudioManager
audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS).find { device ->
device.id == it.toInt()
}
}
}
}

return super.onStartCommand(intent, flags, startId)
}

companion object {
fun changeAudioDevice(deviceID: String?, context: Context) {
val intent = Intent("changeAudioDevice").apply {
putExtra("deviceID", deviceID ?: "null")
}
context.startService(intent)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package app.myzel394.alibi.ui.components.AudioRecorder.atoms

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import app.myzel394.alibi.ui.utils.MicrophoneInfo
import androidx.compose.ui.Alignment
import androidx.compose.ui.res.stringResource
import app.myzel394.alibi.R

@Composable
fun MicrophoneSelectionButton(
microphone: MicrophoneInfo? = null,
selected: Boolean = false,
onSelect: () -> Unit,
) {
Button(
onClick = onSelect,
modifier = Modifier
.fillMaxWidth()
.height(64.dp),
colors = if (selected) ButtonDefaults.buttonColors(
) else ButtonDefaults.textButtonColors(),
) {
MicrophoneTypeInfo(
type = microphone?.type ?: MicrophoneInfo.MicrophoneType.PHONE,
modifier = Modifier.size(ButtonDefaults.IconSize),
)
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text(
text = microphone?.name
?: stringResource(R.string.ui_audioRecorder_info_microphone_deviceMicrophone),
fontSize = MaterialTheme.typography.bodyLarge.fontSize,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package app.myzel394.alibi.ui.components.AudioRecorder.atoms

import android.R
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.BluetoothAudio
import androidx.compose.material.icons.filled.Memory
import androidx.compose.material.icons.filled.Mic
import androidx.compose.material.icons.filled.MicExternalOn
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.filled.Smartphone
import androidx.compose.material.icons.filled.Warning
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import app.myzel394.alibi.ui.utils.MicrophoneInfo

@Composable
fun MicrophoneTypeInfo(
modifier: Modifier = Modifier,
type: MicrophoneInfo.MicrophoneType,
) {
Icon(
imageVector = when (type) {
MicrophoneInfo.MicrophoneType.BLUETOOTH -> Icons.Filled.BluetoothAudio
MicrophoneInfo.MicrophoneType.WIRED -> Icons.Filled.MicExternalOn
MicrophoneInfo.MicrophoneType.PHONE -> Icons.Filled.Smartphone
MicrophoneInfo.MicrophoneType.OTHER -> Icons.Filled.Mic
},
modifier = modifier,
contentDescription = null,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package app.myzel394.alibi.ui.components.AudioRecorder.molecules

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import app.myzel394.alibi.R
import app.myzel394.alibi.ui.components.AudioRecorder.atoms.MicrophoneSelectionButton
import app.myzel394.alibi.ui.components.AudioRecorder.atoms.MicrophoneTypeInfo
import app.myzel394.alibi.ui.models.AudioRecorderModel
import app.myzel394.alibi.ui.utils.MicrophoneInfo

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MicrophoneSelection(
audioRecorder: AudioRecorderModel,
microphones: List<MicrophoneInfo>,
) {
var showSelection by rememberSaveable {
mutableStateOf(false)
}

if (showSelection) {
ModalBottomSheet(
onDismissRequest = {
showSelection = false
}
) {
Column(
modifier = Modifier
.padding(horizontal = 16.dp)
.padding(bottom = 24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(48.dp),
) {
Text(
stringResource(R.string.ui_audioRecorder_info_microphone_changeExplanation),
style = MaterialTheme.typography.bodySmall,
textAlign = TextAlign.Center,
)

LazyColumn(
modifier = Modifier
.padding(horizontal = 32.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
item {
MicrophoneSelectionButton(
selected = audioRecorder.recorderService!!.selectedDevice == null,
onSelect = {
audioRecorder.changeMicrophone(null)
showSelection = false
}
)
}

items(microphones.size) {
val microphone = microphones[it]

MicrophoneSelectionButton(
microphone = microphone,
selected = audioRecorder.recorderService!!.selectedDevice == microphone,
onSelect = {
audioRecorder.changeMicrophone(microphone)
showSelection = false
},
)
}
}
}
}
}

Button(
onClick = {
showSelection = true
},
colors = ButtonDefaults.textButtonColors(),
) {
MicrophoneTypeInfo(
type = audioRecorder.recorderService!!.selectedDevice?.type
?: MicrophoneInfo.MicrophoneType.PHONE,
modifier = Modifier.size(ButtonDefaults.IconSize),
)
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text(
text = audioRecorder.recorderService!!.selectedDevice.let {
it?.name
?: stringResource(R.string.ui_audioRecorder_info_microphone_deviceMicrophone)
}
)
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package app.myzel394.alibi.ui.components.AudioRecorder.molecules
package app.myzel394.alibi.ui.components.AudioRecorder.organisms

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandHorizontally
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
Expand All @@ -26,14 +24,12 @@ import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.Save
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.LargeFloatingActionButton
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand All @@ -50,20 +46,17 @@ import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import app.myzel394.alibi.R
import app.myzel394.alibi.services.RecorderService
import app.myzel394.alibi.ui.BIG_PRIMARY_BUTTON_SIZE
import app.myzel394.alibi.ui.components.AudioRecorder.atoms.ConfirmDeletionDialog
import app.myzel394.alibi.ui.components.AudioRecorder.atoms.RealtimeAudioVisualizer
import app.myzel394.alibi.ui.components.AudioRecorder.atoms.SaveRecordingButton
import app.myzel394.alibi.ui.components.AudioRecorder.molecules.MicrophoneSelection
import app.myzel394.alibi.ui.components.atoms.Pulsating
import app.myzel394.alibi.ui.models.AudioRecorderModel
import app.myzel394.alibi.ui.utils.KeepScreenOn
import app.myzel394.alibi.ui.utils.MicrophoneInfo
import app.myzel394.alibi.ui.utils.formatDuration
import kotlinx.coroutines.delay
import java.io.File
import java.time.Duration
import java.time.LocalDateTime
import java.time.ZoneId

@Composable
fun RecordingStatus(
Expand Down Expand Up @@ -215,5 +208,14 @@ fun RecordingStatus(
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text(stringResource(R.string.ui_audioRecorder_action_save_label))
}

val microphones = MicrophoneInfo.fetchDeviceMicrophones(context)

if (microphones.isNotEmpty()) {
MicrophoneSelection(
audioRecorder = audioRecorder,
microphones = microphones
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.media.MediaRecorder
import android.os.IBinder
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
Expand All @@ -17,6 +14,7 @@ import app.myzel394.alibi.db.LastRecording
import app.myzel394.alibi.enums.RecorderState
import app.myzel394.alibi.services.AudioRecorderService
import app.myzel394.alibi.services.RecorderService
import app.myzel394.alibi.ui.utils.MicrophoneInfo

class AudioRecorderModel: ViewModel() {
var recorderState by mutableStateOf(RecorderState.IDLE)
Expand Down Expand Up @@ -121,6 +119,10 @@ class AudioRecorderModel: ViewModel() {
recorderService?.amplitudesAmount = amount
}

fun changeMicrophone(microphone: MicrophoneInfo?) {
recorderService!!.selectedDevice = microphone
}

fun bindToService(context: Context) {
Intent(context, AudioRecorderService::class.java).also { intent ->
context.bindService(intent, connection, 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import app.myzel394.alibi.ui.components.AudioRecorder.molecules.RecordingStatus
import app.myzel394.alibi.ui.components.AudioRecorder.organisms.RecordingStatus
import app.myzel394.alibi.ui.components.AudioRecorder.molecules.StartRecording
import app.myzel394.alibi.ui.enums.Screen
import app.myzel394.alibi.ui.utils.rememberFileSaverDialog
import app.myzel394.alibi.R
import app.myzel394.alibi.dataStore
import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.db.LastRecording
import app.myzel394.alibi.ui.effects.rememberSettings
import app.myzel394.alibi.ui.models.AudioRecorderModel
import kotlinx.coroutines.launch
Expand Down
Loading

0 comments on commit df1d7ce

Please sign in to comment.