feat: Add microphone connectivity status

This commit is contained in:
Myzel394 2023-10-21 20:37:27 +02:00
parent 825f0eb33f
commit 78453f1c4d
No known key found for this signature in database
GPG Key ID: 79CC92F37B3E1A2B
3 changed files with 85 additions and 0 deletions

View File

@ -1,11 +1,20 @@
package app.myzel394.alibi.services package app.myzel394.alibi.services
import android.annotation.SuppressLint
import android.content.Context
import android.media.AudioDeviceCallback
import android.media.AudioDeviceInfo
import android.media.AudioManager import android.media.AudioManager
import android.media.MediaRecorder import android.media.MediaRecorder
import android.media.MediaRecorder.OnErrorListener import android.media.MediaRecorder.OnErrorListener
import android.os.Build import android.os.Build
import android.os.Handler
import android.os.Looper
import androidx.core.content.ContextCompat.getSystemService
import app.myzel394.alibi.enums.RecorderState
import app.myzel394.alibi.ui.utils.MicrophoneInfo import app.myzel394.alibi.ui.utils.MicrophoneInfo
import java.lang.IllegalStateException import java.lang.IllegalStateException
import java.util.concurrent.Executor
class AudioRecorderService : IntervalRecorderService() { class AudioRecorderService : IntervalRecorderService() {
var amplitudesAmount = 1000 var amplitudesAmount = 1000
@ -15,6 +24,8 @@ class AudioRecorderService : IntervalRecorderService() {
private set private set
var onError: () -> Unit = {} var onError: () -> Unit = {}
var onSelectedMicrophoneChange: (MicrophoneInfo?) -> Unit = {} var onSelectedMicrophoneChange: (MicrophoneInfo?) -> Unit = {}
var onMicrophoneDisconnected: () -> Unit = {}
var onMicrophoneReconnected: () -> Unit = {}
val filePath: String val filePath: String
get() = "$folder/$counter.${settings!!.fileExtension}" get() = "$folder/$counter.${settings!!.fileExtension}"
@ -95,6 +106,12 @@ class AudioRecorderService : IntervalRecorderService() {
} }
} }
override fun start() {
super.start()
registerMicrophoneListener()
}
override fun pause() { override fun pause() {
super.pause() super.pause()
@ -106,6 +123,7 @@ class AudioRecorderService : IntervalRecorderService() {
resetRecorder() resetRecorder()
selectedMicrophone = null selectedMicrophone = null
unregisterMicrophoneListener()
} }
override fun getAmplitudeAmount(): Int = amplitudesAmount override fun getAmplitudeAmount(): Int = amplitudesAmount
@ -123,5 +141,51 @@ class AudioRecorderService : IntervalRecorderService() {
fun changeMicrophone(microphone: MicrophoneInfo?) { fun changeMicrophone(microphone: MicrophoneInfo?) {
selectedMicrophone = microphone selectedMicrophone = microphone
onSelectedMicrophoneChange(microphone) onSelectedMicrophoneChange(microphone)
if (state == RecorderState.RECORDING) {
startNewCycle()
}
}
private val audioDeviceCallback = object : AudioDeviceCallback() {
override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>?) {
super.onAudioDevicesAdded(addedDevices)
if (selectedMicrophone == null) {
return;
}
if (addedDevices?.find { it.id == selectedMicrophone!!.deviceInfo.id } != null) {
onMicrophoneReconnected()
}
}
override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>?) {
super.onAudioDevicesRemoved(removedDevices)
if (selectedMicrophone == null) {
return;
}
if (removedDevices?.find { it.id == selectedMicrophone!!.deviceInfo.id } != null) {
onMicrophoneDisconnected()
}
}
}
@SuppressLint("NewApi")
private fun registerMicrophoneListener() {
val audioManager = getSystemService(Context.AUDIO_SERVICE)!! as AudioManager
audioManager.registerAudioDeviceCallback(
audioDeviceCallback,
Handler(Looper.getMainLooper())
)
}
private fun unregisterMicrophoneListener() {
val audioManager = getSystemService(Context.AUDIO_SERVICE)!! as AudioManager
audioManager.unregisterAudioDeviceCallback(audioDeviceCallback)
} }
} }

View File

@ -46,6 +46,14 @@ class AudioRecorderModel : ViewModel() {
var onRecordingSave: () -> Unit = {} var onRecordingSave: () -> Unit = {}
var onError: () -> Unit = {} var onError: () -> Unit = {}
var microphoneStatus: MicrophoneConnectivityStatus = MicrophoneConnectivityStatus.CONNECTED
private set
enum class MicrophoneConnectivityStatus {
CONNECTED,
DISCONNECTED
}
private val connection = object : ServiceConnection { private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) { override fun onServiceConnected(className: ComponentName, service: IBinder) {
recorderService = recorderService =
@ -68,6 +76,12 @@ class AudioRecorderModel : ViewModel() {
recorder.onSelectedMicrophoneChange = { microphone -> recorder.onSelectedMicrophoneChange = { microphone ->
selectedMicrophone = microphone selectedMicrophone = microphone
} }
recorder.onMicrophoneDisconnected = {
microphoneStatus = MicrophoneConnectivityStatus.DISCONNECTED
}
recorder.onMicrophoneReconnected = {
microphoneStatus = MicrophoneConnectivityStatus.CONNECTED
}
}.also { }.also {
// Init UI from the service // Init UI from the service
it.startRecording() it.startRecording()
@ -90,6 +104,7 @@ class AudioRecorderModel : ViewModel() {
recordingTime = null recordingTime = null
amplitudes = emptyList() amplitudes = emptyList()
selectedMicrophone = null selectedMicrophone = null
microphoneStatus = MicrophoneConnectivityStatus.CONNECTED
} }
fun startRecording(context: Context) { fun startRecording(context: Context) {
@ -131,6 +146,10 @@ class AudioRecorderModel : ViewModel() {
fun changeMicrophone(microphone: MicrophoneInfo?) { fun changeMicrophone(microphone: MicrophoneInfo?) {
recorderService!!.changeMicrophone(microphone) recorderService!!.changeMicrophone(microphone)
if (microphone == null) {
microphoneStatus = MicrophoneConnectivityStatus.CONNECTED
}
} }
fun bindToService(context: Context) { fun bindToService(context: Context) {

View File

@ -65,4 +65,6 @@
<string name="ui_settings_language_update_label">Change</string> <string name="ui_settings_language_update_label">Change</string>
<string name="ui_audioRecorder_info_microphone_deviceMicrophone">Device Microphone</string> <string name="ui_audioRecorder_info_microphone_deviceMicrophone">Device Microphone</string>
<string name="ui_audioRecorder_info_microphone_changeExplanation">The selected microphone will be immediately activated</string> <string name="ui_audioRecorder_info_microphone_changeExplanation">The selected microphone will be immediately activated</string>
<string name="ui_audioRecorder_error_microphoneDisconnected_title">Microphone disconnected</string>
<string name="ui_audioRecorder_error_microphoneDisconnected_message"><xliff:g name="name">%s</xliff:g> disconnected. Alibi will use the default microphone instead. We will automatically switch back to <xliff:g name="name">%s</xliff:g> once it reconnects.</string>
</resources> </resources>