diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/call/CallView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/call/CallView.kt index 036228cb6..b6f529600 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/call/CallView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/call/CallView.kt @@ -1,6 +1,8 @@ package chat.simplex.app.views.call import android.Manifest +import android.content.Context +import android.media.AudioManager import android.util.Log import android.view.ViewGroup import android.webkit.* @@ -35,6 +37,7 @@ import chat.simplex.app.views.helpers.ProfileImage import chat.simplex.app.views.helpers.withApi import com.google.accompanist.permissions.rememberMultiplePermissionsState import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString @@ -44,6 +47,8 @@ fun ActiveCallView(chatModel: ChatModel) { val call = chatModel.activeCall.value if (call != null) withApi { chatModel.callManager.endCall(call) } }) + val cxt = LocalContext.current + val scope = rememberCoroutineScope() Box(Modifier.fillMaxSize()) { WebRTCView(chatModel.callCommand) { apiMsg -> Log.d(TAG, "received from WebRTCView: $apiMsg") @@ -79,6 +84,10 @@ fun ActiveCallView(chatModel: ChatModel) { } is WCallResponse.Connected -> { chatModel.activeCall.value = call.copy(callState = CallState.Connected, connectionInfo = r.connectionInfo) + scope.launch { + delay(2000L) + setCallSound(cxt, call) + } } is WCallResponse.Ended -> { chatModel.activeCall.value = call.copy(callState = CallState.Ended) @@ -117,21 +126,43 @@ fun ActiveCallView(chatModel: ChatModel) { @Composable private fun ActiveCallOverlay(call: Call, chatModel: ChatModel) { + var cxt = LocalContext.current ActiveCallOverlayLayout( call = call, dismiss = { withApi { chatModel.callManager.endCall(call) } }, toggleAudio = { chatModel.callCommand.value = WCallCommand.Media(CallMediaType.Audio, enable = !call.audioEnabled) }, toggleVideo = { chatModel.callCommand.value = WCallCommand.Media(CallMediaType.Video, enable = !call.videoEnabled) }, + toggleSound = { + var call = chatModel.activeCall.value + if (call != null) { + call = call.copy(soundSpeaker = !call.soundSpeaker) + chatModel.activeCall.value = call + setCallSound(cxt, call) + } + }, flipCamera = { chatModel.callCommand.value = WCallCommand.Camera(call.localCamera.flipped) } ) } +private fun setCallSound(cxt: Context, call: Call) { + Log.d(TAG, "setCallSound: set audio mode") + val am = cxt.getSystemService(Context.AUDIO_SERVICE) as AudioManager + if (call.soundSpeaker) { + am.mode = AudioManager.MODE_NORMAL + am.isSpeakerphoneOn = true + } else { + am.mode = AudioManager.MODE_IN_CALL + am.isSpeakerphoneOn = false + } +} + @Composable private fun ActiveCallOverlayLayout( call: Call, dismiss: () -> Unit, toggleAudio: () -> Unit, toggleVideo: () -> Unit, + toggleSound: () -> Unit, flipCamera: () -> Unit ) { Column(Modifier.padding(16.dp)) { @@ -174,6 +205,11 @@ private fun ActiveCallOverlayLayout( Box(Modifier.padding(start = 32.dp)) { ToggleAudioButton(call, toggleAudio) } + Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.CenterEnd) { + Box(Modifier.padding(end = 32.dp)) { + ToggleSoundButton(call, toggleSound) + } + } } } } @@ -194,12 +230,21 @@ private fun ControlButton(call: Call, icon: ImageVector, @StringRes iconText: In @Composable private fun ToggleAudioButton(call: Call, toggleAudio: () -> Unit) { if (call.audioEnabled) { - ControlButton(call, Icons.Outlined.Mic, R.string.icon_descr_video_off, toggleAudio) + ControlButton(call, Icons.Outlined.Mic, R.string.icon_descr_audio_off, toggleAudio) } else { ControlButton(call, Icons.Outlined.MicOff, R.string.icon_descr_audio_on, toggleAudio) } } +@Composable +private fun ToggleSoundButton(call: Call, toggleSound: () -> Unit) { + if (call.soundSpeaker) { + ControlButton(call, Icons.Outlined.VolumeUp, R.string.icon_descr_speaker_off, toggleSound) + } else { + ControlButton(call, Icons.Outlined.VolumeDown, R.string.icon_descr_speaker_on, toggleSound) + } +} + @Composable fun CallInfoView(call: Call, alignment: Alignment.Horizontal) { @Composable fun InfoText(text: String, style: TextStyle = MaterialTheme.typography.body2) = @@ -393,6 +438,7 @@ fun PreviewActiveCallOverlayVideo() { dismiss = {}, toggleAudio = {}, toggleVideo = {}, + toggleSound = {}, flipCamera = {} ) } @@ -413,6 +459,7 @@ fun PreviewActiveCallOverlayAudio() { dismiss = {}, toggleAudio = {}, toggleVideo = {}, + toggleSound = {}, flipCamera = {} ) } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/call/WebRTC.kt b/apps/android/app/src/main/java/chat/simplex/app/views/call/WebRTC.kt index afef4ca82..bb079e800 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/call/WebRTC.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/call/WebRTC.kt @@ -18,6 +18,7 @@ data class Call( val sharedKey: String? = null, val audioEnabled: Boolean = true, val videoEnabled: Boolean = localMedia == CallMediaType.Video, + val soundSpeaker: Boolean = localMedia == CallMediaType.Video, var localCamera: VideoCamera = VideoCamera.User, val connectionInfo: ConnectionInfo? = null ) { diff --git a/apps/android/app/src/main/res/values-ru/strings.xml b/apps/android/app/src/main/res/values-ru/strings.xml index 16269f27a..c6a916f6c 100644 --- a/apps/android/app/src/main/res/values-ru/strings.xml +++ b/apps/android/app/src/main/res/values-ru/strings.xml @@ -404,6 +404,8 @@ Включить видео Выключить звук Включить звук + Выключить спикер + Включить спикер Перевернуть камеру diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index 284fd2ca8..e327f0feb 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -406,6 +406,8 @@ Video on Audio off Audio on + Speaker off + Speaker on Flip camera