From 4d5deff487a84f1b3a521c458afa113fc8157bb3 Mon Sep 17 00:00:00 2001 From: Avently <7953703+avently@users.noreply.github.com> Date: Sun, 7 Apr 2024 01:20:02 +0700 Subject: [PATCH] android, desktop: sound prompts and vibration --- .../simplex/common/helpers/SoundPlayer.kt | 68 ++++++++++++++++-- .../common/platform/RecAndPlay.android.kt | 1 + .../common/views/call/CallView.android.kt | 22 +++++- .../res/raw/call_sound_before_answer.mp3 | Bin 0 -> 78240 bytes .../simplex/common/platform/RecAndPlay.kt | 8 +++ .../common/platform/RecAndPlay.desktop.kt | 32 +++++++++ .../media/call_sound_before_answer.mp3 | Bin 0 -> 78240 bytes 7 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 apps/multiplatform/common/src/androidMain/res/raw/call_sound_before_answer.mp3 create mode 100644 apps/multiplatform/common/src/desktopMain/resources/media/call_sound_before_answer.mp3 diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/helpers/SoundPlayer.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/helpers/SoundPlayer.kt index ff83c10df3..a43fac29e3 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/helpers/SoundPlayer.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/helpers/SoundPlayer.kt @@ -2,17 +2,15 @@ package chat.simplex.common.helpers import android.media.* import android.net.Uri -import android.os.VibrationEffect -import android.os.Vibrator +import android.os.* import androidx.core.content.ContextCompat import chat.simplex.common.R -import chat.simplex.common.platform.SoundPlayerInterface -import chat.simplex.common.platform.androidAppContext +import chat.simplex.common.platform.* import kotlinx.coroutines.* object SoundPlayer: SoundPlayerInterface { private var player: MediaPlayer? = null - var playing = false + private var playing = false override fun start(scope: CoroutineScope, sound: Boolean) { player?.reset() @@ -32,7 +30,7 @@ object SoundPlayer: SoundPlayerInterface { scope.launch { while (playing) { if (sound) player?.start() - vibrator?.vibrate(effect) + vibrator?.vibrateApiVersionAware(effect) delay(3500) } } @@ -43,3 +41,61 @@ object SoundPlayer: SoundPlayerInterface { player?.stop() } } + +object CallSoundsPlayer: CallSoundsPlayerInterface { + private var player: MediaPlayer? = null + private var playing = false + + override fun startWaitingAnswerSound(scope: CoroutineScope) { + player?.reset() + player = MediaPlayer().apply { + setAudioAttributes( + AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING) + .build() + ) + setDataSource(androidAppContext, Uri.parse("android.resource://" + androidAppContext.packageName + "/" + R.raw.call_sound_before_answer)) + prepare() + } + playing = true + scope.launch { + while (playing) { + player?.start() + delay(2000) + } + } + } + + override fun vibrate() { + val vibrator = ContextCompat.getSystemService(androidAppContext, Vibrator::class.java) + val effect = VibrationEffect.createOneShot(50, VibrationEffect.DEFAULT_AMPLITUDE) + vibrator?.vibrateApiVersionAware(effect) + } + + override fun stop() { + playing = false + player?.stop() + } +} + +private fun Vibrator.vibrateApiVersionAware(effect: VibrationEffect) { + if (Build.VERSION.SDK_INT >= 33) { + vibrate( + effect, + VibrationAttributes.Builder() + .setUsage(VibrationAttributes.USAGE_ALARM) + .build() + ) + } else if (Build.VERSION.SDK_INT >= 29) { + vibrate( + effect, + AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setUsage(AudioAttributes.USAGE_ALARM) + .build() + ) + } else { + vibrate(effect) + } +} diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/RecAndPlay.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/RecAndPlay.android.kt index 5b0d3c778f..5cb10ff070 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/RecAndPlay.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/platform/RecAndPlay.android.kt @@ -296,6 +296,7 @@ actual object AudioPlayer: AudioPlayerInterface { } actual typealias SoundPlayer = chat.simplex.common.helpers.SoundPlayer +actual typealias CallSoundsPlayer = chat.simplex.common.helpers.CallSoundsPlayer class CryptoMediaSource(val data: ByteArray) : MediaDataSource() { override fun readAt(position: Long, buffer: ByteArray, offset: Int, size: Int): Int { diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt index b0c4beded0..2a11c09c95 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt @@ -69,6 +69,8 @@ fun activeCallDestroyWebView() = withApi { @SuppressLint("SourceLockedOrientationActivity") @Composable actual fun ActiveCallView() { + val call = remember { chatModel.activeCall }.value + val scope = rememberCoroutineScope() val audioViaBluetooth = rememberSaveable { mutableStateOf(false) } val proximityLock = remember { val pm = (androidAppContext.getSystemService(Context.POWER_SERVICE) as PowerManager) @@ -78,6 +80,16 @@ actual fun ActiveCallView() { null } } + val wasConnected = rememberSaveable { mutableStateOf(false) } + LaunchedEffect(call) { + if (call?.callState == CallState.Connected && !wasConnected.value) { + CallSoundsPlayer.vibrate() + wasConnected.value = true + } + if ((call?.callState ?: CallState.WaitCapabilities) >= CallState.OfferReceived) { + CallSoundsPlayer.stop() + } + } DisposableEffect(Unit) { val am = androidAppContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager var btDeviceCount = 0 @@ -106,7 +118,15 @@ actual fun ActiveCallView() { } } am.registerAudioDeviceCallback(audioCallback, null) + if (call?.callState == CallState.WaitCapabilities || call?.callState == CallState.InvitationSent) { + setCallSound(call.soundSpeaker, audioViaBluetooth) + CallSoundsPlayer.startWaitingAnswerSound(scope) + } onDispose { + CallSoundsPlayer.stop() + if (wasConnected.value) { + CallSoundsPlayer.vibrate() + } dropAudioManagerOverrides() am.unregisterAudioDeviceCallback(audioCallback) if (proximityLock?.isHeld == true) { @@ -122,8 +142,6 @@ actual fun ActiveCallView() { if (proximityLock?.isHeld == false) proximityLock.acquire() } } - val scope = rememberCoroutineScope() - val call = chatModel.activeCall.value Box(Modifier.fillMaxSize()) { WebRTCView(chatModel.callCommand) { apiMsg -> Log.d(TAG, "received from WebRTCView: $apiMsg") diff --git a/apps/multiplatform/common/src/androidMain/res/raw/call_sound_before_answer.mp3 b/apps/multiplatform/common/src/androidMain/res/raw/call_sound_before_answer.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..b3aa169840a61fd1ebc6eb221eef4418687b3029 GIT binary patch literal 78240 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 literal 0 HcmV?d00001 diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/RecAndPlay.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/RecAndPlay.kt index 0e0f769487..66c6bad03f 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/RecAndPlay.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/RecAndPlay.kt @@ -39,4 +39,12 @@ interface SoundPlayerInterface { fun stop() } +interface CallSoundsPlayerInterface { + fun startWaitingAnswerSound(scope: CoroutineScope) + fun stop() + fun vibrate() +} + expect object SoundPlayer: SoundPlayerInterface + +expect object CallSoundsPlayer: CallSoundsPlayerInterface diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/RecAndPlay.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/RecAndPlay.desktop.kt index 50d143aaf5..e936b35789 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/RecAndPlay.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/RecAndPlay.desktop.kt @@ -228,3 +228,35 @@ actual object SoundPlayer: SoundPlayerInterface { AudioPlayer.stop() } } + +actual object CallSoundsPlayer: CallSoundsPlayerInterface { + private var player: MediaPlayer? = null + private var playing = false + + override fun startWaitingAnswerSound(scope: CoroutineScope) { + val tmpFile = File(tmpDir, UUID.randomUUID().toString()) + tmpFile.deleteOnExit() + SoundPlayer::class.java.getResource("/media/call_sound_before_answer.mp3").openStream()!!.use { it.copyTo(tmpFile.outputStream()) } + SoundPlayer.playing = true + scope.launch { + while (SoundPlayer.playing) { + AudioPlayer.play(CryptoFile.plain(tmpFile.absolutePath), mutableStateOf(true), mutableStateOf(0), mutableStateOf(0), true) + delay(3500) + } + } + playing = true + scope.launch { + while (playing) { + player?.start() + delay(3500) + } + } + } + + override fun vibrate() {} + + override fun stop() { + playing = false + AudioPlayer.stop() + } +} diff --git a/apps/multiplatform/common/src/desktopMain/resources/media/call_sound_before_answer.mp3 b/apps/multiplatform/common/src/desktopMain/resources/media/call_sound_before_answer.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..b3aa169840a61fd1ebc6eb221eef4418687b3029 GIT binary patch literal 78240 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 literal 0 HcmV?d00001