From 78453f1c4d6570b2845bc2cc7667299da1ce1c15 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sat, 21 Oct 2023 20:37:27 +0200 Subject: [PATCH] feat: Add microphone connectivity status --- .../alibi/services/AudioRecorderService.kt | 64 +++++++++++++++++++ .../alibi/ui/models/AudioRecorderModel.kt | 19 ++++++ app/src/main/res/values/strings.xml | 2 + 3 files changed, 85 insertions(+) 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 0a39a03..f95b913 100644 --- a/app/src/main/java/app/myzel394/alibi/services/AudioRecorderService.kt +++ b/app/src/main/java/app/myzel394/alibi/services/AudioRecorderService.kt @@ -1,11 +1,20 @@ 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.MediaRecorder import android.media.MediaRecorder.OnErrorListener 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 java.lang.IllegalStateException +import java.util.concurrent.Executor class AudioRecorderService : IntervalRecorderService() { var amplitudesAmount = 1000 @@ -15,6 +24,8 @@ class AudioRecorderService : IntervalRecorderService() { private set var onError: () -> Unit = {} var onSelectedMicrophoneChange: (MicrophoneInfo?) -> Unit = {} + var onMicrophoneDisconnected: () -> Unit = {} + var onMicrophoneReconnected: () -> Unit = {} val filePath: String get() = "$folder/$counter.${settings!!.fileExtension}" @@ -95,6 +106,12 @@ class AudioRecorderService : IntervalRecorderService() { } } + override fun start() { + super.start() + + registerMicrophoneListener() + } + override fun pause() { super.pause() @@ -106,6 +123,7 @@ class AudioRecorderService : IntervalRecorderService() { resetRecorder() selectedMicrophone = null + unregisterMicrophoneListener() } override fun getAmplitudeAmount(): Int = amplitudesAmount @@ -123,5 +141,51 @@ class AudioRecorderService : IntervalRecorderService() { fun changeMicrophone(microphone: MicrophoneInfo?) { selectedMicrophone = microphone onSelectedMicrophoneChange(microphone) + + if (state == RecorderState.RECORDING) { + startNewCycle() + } + } + + private val audioDeviceCallback = object : AudioDeviceCallback() { + override fun onAudioDevicesAdded(addedDevices: Array?) { + super.onAudioDevicesAdded(addedDevices) + + if (selectedMicrophone == null) { + return; + } + + if (addedDevices?.find { it.id == selectedMicrophone!!.deviceInfo.id } != null) { + onMicrophoneReconnected() + } + } + + override fun onAudioDevicesRemoved(removedDevices: Array?) { + 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) } } \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt b/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt index 2c1c718..6fcb718 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt @@ -46,6 +46,14 @@ class AudioRecorderModel : ViewModel() { var onRecordingSave: () -> Unit = {} var onError: () -> Unit = {} + var microphoneStatus: MicrophoneConnectivityStatus = MicrophoneConnectivityStatus.CONNECTED + private set + + enum class MicrophoneConnectivityStatus { + CONNECTED, + DISCONNECTED + } + private val connection = object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { recorderService = @@ -68,6 +76,12 @@ class AudioRecorderModel : ViewModel() { recorder.onSelectedMicrophoneChange = { microphone -> selectedMicrophone = microphone } + recorder.onMicrophoneDisconnected = { + microphoneStatus = MicrophoneConnectivityStatus.DISCONNECTED + } + recorder.onMicrophoneReconnected = { + microphoneStatus = MicrophoneConnectivityStatus.CONNECTED + } }.also { // Init UI from the service it.startRecording() @@ -90,6 +104,7 @@ class AudioRecorderModel : ViewModel() { recordingTime = null amplitudes = emptyList() selectedMicrophone = null + microphoneStatus = MicrophoneConnectivityStatus.CONNECTED } fun startRecording(context: Context) { @@ -131,6 +146,10 @@ class AudioRecorderModel : ViewModel() { fun changeMicrophone(microphone: MicrophoneInfo?) { recorderService!!.changeMicrophone(microphone) + + if (microphone == null) { + microphoneStatus = MicrophoneConnectivityStatus.CONNECTED + } } fun bindToService(context: Context) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fc63b3a..653871b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -65,4 +65,6 @@ Change Device Microphone The selected microphone will be immediately activated + Microphone disconnected + %s disconnected. Alibi will use the default microphone instead. We will automatically switch back to %s once it reconnects. \ No newline at end of file