Fixes for self-mute during remote conference + rework how we mute single call

This commit is contained in:
Sylvain Berfini 2022-05-04 15:22:51 +02:00
parent 18f36b85bb
commit d6f83f0057
7 changed files with 78 additions and 51 deletions

View file

@ -83,26 +83,6 @@ class CallActivity : ProximitySensorActivity() {
statsViewModel = ViewModelProvider(navControllerStoreOwner)[StatisticsListViewModel::class.java] statsViewModel = ViewModelProvider(navControllerStoreOwner)[StatisticsListViewModel::class.java]
callsViewModel.noMoreCallEvent.observe(
this
) {
it.consume { noMoreCall ->
if (noMoreCall) {
Log.i("[Call Activity] No more call event fired, finishing activity")
finish()
}
}
}
callsViewModel.askWriteExternalStoragePermissionEvent.observe(
this
) {
it.consume {
Log.i("[Call Activity] Asking for WRITE_EXTERNAL_STORAGE permission to take snapshot")
requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 1)
}
}
controlsViewModel.askPermissionEvent.observe( controlsViewModel.askPermissionEvent.observe(
this this
) { ) {
@ -136,6 +116,26 @@ class CallActivity : ProximitySensorActivity() {
if (visible) statsViewModel.enable() else statsViewModel.disable() if (visible) statsViewModel.enable() else statsViewModel.disable()
} }
callsViewModel.noMoreCallEvent.observe(
this
) {
it.consume { noMoreCall ->
if (noMoreCall) {
Log.i("[Call Activity] No more call event fired, finishing activity")
finish()
}
}
}
callsViewModel.askWriteExternalStoragePermissionEvent.observe(
this
) {
it.consume {
Log.i("[Call Activity] Asking for WRITE_EXTERNAL_STORAGE permission to take snapshot")
requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 1)
}
}
callsViewModel.currentCallData.observe( callsViewModel.currentCallData.observe(
this this
) { callData -> ) { callData ->
@ -148,6 +148,15 @@ class CallActivity : ProximitySensorActivity() {
} }
} }
callsViewModel.askPermissionEvent.observe(
this
) {
it.consume { permission ->
Log.i("[Call Activity] Asking for $permission permission")
requestPermissions(arrayOf(permission), 0)
}
}
conferenceViewModel.conferenceExists.observe( conferenceViewModel.conferenceExists.observe(
this this
) { exists -> ) { exists ->
@ -281,7 +290,7 @@ class CallActivity : ProximitySensorActivity() {
when (permissions[i]) { when (permissions[i]) {
Manifest.permission.RECORD_AUDIO -> if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { Manifest.permission.RECORD_AUDIO -> if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
Log.i("[Call Activity] RECORD_AUDIO permission has been granted") Log.i("[Call Activity] RECORD_AUDIO permission has been granted")
controlsViewModel.updateMicState() callsViewModel.updateMicState()
} }
Manifest.permission.CAMERA -> if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { Manifest.permission.CAMERA -> if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
Log.i("[Call Activity] CAMERA permission has been granted") Log.i("[Call Activity] CAMERA permission has been granted")

View file

@ -19,6 +19,7 @@
*/ */
package org.linphone.activities.voip.viewmodels package org.linphone.activities.voip.viewmodels
import android.Manifest
import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
@ -43,6 +44,10 @@ class CallsViewModel : ViewModel() {
val chatAndCallsCount = MediatorLiveData<Int>() val chatAndCallsCount = MediatorLiveData<Int>()
val isMicrophoneMuted = MutableLiveData<Boolean>()
val isMuteMicrophoneEnabled = MutableLiveData<Boolean>()
val askWriteExternalStoragePermissionEvent: MutableLiveData<Event<Boolean>> by lazy { val askWriteExternalStoragePermissionEvent: MutableLiveData<Event<Boolean>> by lazy {
MutableLiveData<Event<Boolean>>() MutableLiveData<Event<Boolean>>()
} }
@ -63,6 +68,10 @@ class CallsViewModel : ViewModel() {
MutableLiveData<Event<Boolean>>() MutableLiveData<Event<Boolean>>()
} }
val askPermissionEvent: MutableLiveData<Event<String>> by lazy {
MutableLiveData<Event<String>>()
}
private val listener = object : CoreListenerStub() { private val listener = object : CoreListenerStub() {
override fun onChatRoomRead(core: Core, chatRoom: ChatRoom) { override fun onChatRoomRead(core: Core, chatRoom: ChatRoom) {
updateUnreadChatCount() updateUnreadChatCount()
@ -145,6 +154,7 @@ class CallsViewModel : ViewModel() {
initCallList() initCallList()
updateInactiveCallsCount() updateInactiveCallsCount()
updateUnreadChatCount() updateUnreadChatCount()
updateMicState()
} }
override fun onCleared() { override fun onCleared() {
@ -156,6 +166,17 @@ class CallsViewModel : ViewModel() {
super.onCleared() super.onCleared()
} }
fun toggleMuteMicrophone() {
if (!PermissionHelper.get().hasRecordAudioPermission()) {
askPermissionEvent.value = Event(Manifest.permission.RECORD_AUDIO)
return
}
val micMuted = currentCallData.value?.call?.microphoneMuted ?: false
currentCallData.value?.call?.microphoneMuted = !micMuted
updateMicState()
}
fun mergeCallsIntoConference() { fun mergeCallsIntoConference() {
Log.i("[Calls] Merging all calls into new conference") Log.i("[Calls] Merging all calls into new conference")
val core = coreContext.core val core = coreContext.core
@ -258,6 +279,7 @@ class CallsViewModel : ViewModel() {
currentCallData.value = viewModel currentCallData.value = viewModel
} }
updateMicState()
// updateUnreadChatCount() // updateUnreadChatCount()
} }
@ -270,6 +292,11 @@ class CallsViewModel : ViewModel() {
return false return false
} }
fun updateMicState() {
isMicrophoneMuted.value = !PermissionHelper.get().hasRecordAudioPermission() || currentCallData.value?.call?.microphoneMuted == true
isMuteMicrophoneEnabled.value = currentCallData.value?.call != null
}
private fun updateCallsAndChatCount(): Int { private fun updateCallsAndChatCount(): Int {
return (inactiveCallsCount.value ?: 0) + (currentCallUnreadChatMessageCount.value ?: 0) return (inactiveCallsCount.value ?: 0) + (currentCallUnreadChatMessageCount.value ?: 0)
} }

View file

@ -37,10 +37,6 @@ import org.linphone.utils.Event
import org.linphone.utils.PermissionHelper import org.linphone.utils.PermissionHelper
class ControlsViewModel : ViewModel() { class ControlsViewModel : ViewModel() {
val isMicrophoneMuted = MutableLiveData<Boolean>()
val isMuteMicrophoneEnabled = MutableLiveData<Boolean>()
val isSpeakerSelected = MutableLiveData<Boolean>() val isSpeakerSelected = MutableLiveData<Boolean>()
val isBluetoothHeadsetSelected = MutableLiveData<Boolean>() val isBluetoothHeadsetSelected = MutableLiveData<Boolean>()
@ -241,17 +237,6 @@ class ControlsViewModel : ViewModel() {
} }
} }
fun toggleMuteMicrophone() {
if (!PermissionHelper.get().hasRecordAudioPermission()) {
askPermissionEvent.value = Event(Manifest.permission.RECORD_AUDIO)
return
}
val micEnabled = coreContext.core.isMicEnabled
coreContext.core.isMicEnabled = !micEnabled
updateMicState()
}
fun toggleSpeaker() { fun toggleSpeaker() {
if (AudioRouteUtils.isSpeakerAudioRouteCurrentlyUsed()) { if (AudioRouteUtils.isSpeakerAudioRouteCurrentlyUsed()) {
forceEarpieceAudioRoute() forceEarpieceAudioRoute()
@ -402,16 +387,10 @@ class ControlsViewModel : ViewModel() {
private fun updateUI() { private fun updateUI() {
updateVideoAvailable() updateVideoAvailable()
updateVideoEnabled() updateVideoEnabled()
updateMicState()
updateSpeakerState() updateSpeakerState()
updateAudioRoutesState() updateAudioRoutesState()
} }
fun updateMicState() {
isMicrophoneMuted.value = !PermissionHelper.get().hasRecordAudioPermission() || !coreContext.core.isMicEnabled
isMuteMicrophoneEnabled.value = coreContext.core.currentCall != null || coreContext.core.conference?.isIn == true
}
private fun updateSpeakerState() { private fun updateSpeakerState() {
isSpeakerSelected.value = AudioRouteUtils.isSpeakerAudioRouteCurrentlyUsed() isSpeakerSelected.value = AudioRouteUtils.isSpeakerAudioRouteCurrentlyUsed()
} }

View file

@ -75,7 +75,14 @@ class NativeCallWrapper(var callId: String) : Connection() {
return return
} }
call.microphoneMuted = state.isMuted if (state.isMuted != call.microphoneMuted) {
Log.w("[Connection] Connection audio state asks for changing in mute: ${state.isMuted}, currently is ${call.microphoneMuted}")
if (state.isMuted) {
Log.w("[Connection] Muting microphone")
call.microphoneMuted = true
}
}
when (state.route) { when (state.route) {
CallAudioState.ROUTE_EARPIECE -> AudioRouteUtils.routeAudioToEarpiece(call, true) CallAudioState.ROUTE_EARPIECE -> AudioRouteUtils.routeAudioToEarpiece(call, true)
CallAudioState.ROUTE_SPEAKER -> AudioRouteUtils.routeAudioToSpeaker(call, true) CallAudioState.ROUTE_SPEAKER -> AudioRouteUtils.routeAudioToSpeaker(call, true)

View file

@ -44,11 +44,11 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginEnd="5dp" android:layout_marginEnd="5dp"
android:background="@drawable/button_background_reverse" android:background="@drawable/button_background_reverse"
android:contentDescription="@{controlsViewModel.isMicrophoneMuted ? @string/content_description_disable_mic_mute : @string/content_description_enable_mic_mute}" android:contentDescription="@{callsViewModel.isMicrophoneMuted ? @string/content_description_disable_mic_mute : @string/content_description_enable_mic_mute}"
android:enabled="@{controlsViewModel.isMuteMicrophoneEnabled}" android:enabled="@{callsViewModel.isMuteMicrophoneEnabled}"
android:onClick="@{() -> controlsViewModel.toggleMuteMicrophone()}" android:onClick="@{() -> callsViewModel.toggleMuteMicrophone()}"
android:padding="5dp" android:padding="5dp"
android:selected="@{controlsViewModel.isMicrophoneMuted}" android:selected="@{callsViewModel.isMicrophoneMuted}"
android:src="@drawable/icon_toggle_mic" android:src="@drawable/icon_toggle_mic"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="W,1:1" app:layout_constraintDimensionRatio="W,1:1"

View file

@ -6,6 +6,10 @@
<import type="android.view.View" /> <import type="android.view.View" />
<variable
name="callsViewModel"
type="org.linphone.activities.voip.viewmodels.CallsViewModel" />
<variable <variable
name="controlsViewModel" name="controlsViewModel"
type="org.linphone.activities.voip.viewmodels.ControlsViewModel" /> type="org.linphone.activities.voip.viewmodels.ControlsViewModel" />
@ -34,11 +38,11 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginEnd="5dp" android:layout_marginEnd="5dp"
android:background="@drawable/button_background_reverse" android:background="@drawable/button_background_reverse"
android:contentDescription="@{controlsViewModel.isMicrophoneMuted ? @string/content_description_disable_mic_mute : @string/content_description_enable_mic_mute}" android:contentDescription="@{callsViewModel.isMicrophoneMuted ? @string/content_description_disable_mic_mute : @string/content_description_enable_mic_mute}"
android:enabled="@{controlsViewModel.isMuteMicrophoneEnabled}" android:enabled="@{callsViewModel.isMuteMicrophoneEnabled}"
android:onClick="@{() -> controlsViewModel.toggleMuteMicrophone()}" android:onClick="@{() -> callsViewModel.toggleMuteMicrophone()}"
android:padding="5dp" android:padding="5dp"
android:selected="@{controlsViewModel.isMicrophoneMuted}" android:selected="@{callsViewModel.isMicrophoneMuted}"
android:src="@drawable/icon_toggle_mic" android:src="@drawable/icon_toggle_mic"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="W,1:1" app:layout_constraintDimensionRatio="W,1:1"

View file

@ -119,6 +119,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="@dimen/voip_buttons_fragment_size" android:layout_height="@dimen/voip_buttons_fragment_size"
android:layout_margin="10dp" android:layout_margin="10dp"
app:callsViewModel="@{callsViewModel}"
app:controlsViewModel="@{controlsViewModel}" app:controlsViewModel="@{controlsViewModel}"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"