From 9fc95743698c301acc73778221cf93c3bc418737 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 5 Sep 2024 10:00:11 +0200 Subject: [PATCH] Added echo canceller calibration & adaptive rate control settings --- .../settings/viewmodel/SettingsViewModel.kt | 71 +++++++++++++++++++ app/src/main/res/layout/settings_calls.xml | 63 +++++++++++++++- app/src/main/res/values-fr/strings.xml | 10 ++- app/src/main/res/values/strings.xml | 10 ++- 4 files changed, 148 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/linphone/ui/main/settings/viewmodel/SettingsViewModel.kt b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/SettingsViewModel.kt index 205e45c06..c52c00362 100644 --- a/app/src/main/java/org/linphone/ui/main/settings/viewmodel/SettingsViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/SettingsViewModel.kt @@ -30,6 +30,7 @@ import org.linphone.core.AudioDevice import org.linphone.core.Conference import org.linphone.core.Core import org.linphone.core.CoreListenerStub +import org.linphone.core.EcCalibratorStatus import org.linphone.core.Factory import org.linphone.core.FriendList import org.linphone.core.Tunnel @@ -67,6 +68,10 @@ class SettingsViewModel @UiThread constructor() : GenericViewModel() { // Calls settings val echoCancellerEnabled = MutableLiveData() + val calibratedEchoCancellerValue = MutableLiveData() + + val adaptiveRateControlEnabled = MutableLiveData() + val videoEnabled = MutableLiveData() val videoFecEnabled = MutableLiveData() @@ -187,12 +192,19 @@ class SettingsViewModel @UiThread constructor() : GenericViewModel() { val videoCodecs = MutableLiveData>() private val coreListener = object : CoreListenerStub() { + @WorkerThread override fun onAudioDevicesListUpdated(core: Core) { Log.i( "$TAG Audio devices list has changed, update available input/output audio devices list" ) setupAudioDevices() } + + @WorkerThread + override fun onEcCalibrationResult(core: Core, status: EcCalibratorStatus, delayMs: Int) { + if (status == EcCalibratorStatus.InProgress) return + echoCancellerCalibrationFinished(status, delayMs) + } } init { @@ -232,6 +244,24 @@ class SettingsViewModel @UiThread constructor() : GenericViewModel() { isUiSecureModeEnabled.postValue(corePreferences.enableSecureMode) echoCancellerEnabled.postValue(core.isEchoCancellationEnabled) + val delay = core.echoCancellationCalibration + if (delay > 0) { + val label = AppUtils.getString( + R.string.settings_calls_calibrate_echo_canceller_done + ).format( + delay + ) + calibratedEchoCancellerValue.postValue(label) + } else if (delay == 0) { + calibratedEchoCancellerValue.postValue( + AppUtils.getString( + R.string.settings_calls_calibrate_echo_canceller_done_no_echo + ) + ) + } + + adaptiveRateControlEnabled.postValue(core.isAdaptiveRateControlEnabled) + videoEnabled.postValue(core.isVideoEnabled) videoFecEnabled.postValue(core.isFecEnabled) vibrateDuringIncomingCall.postValue(core.isVibrationOnIncomingCallEnabled) @@ -312,6 +342,26 @@ class SettingsViewModel @UiThread constructor() : GenericViewModel() { } } + @UiThread + fun calibrateEchoCanceller() { + coreContext.postOnCoreThread { core -> + Log.i("$TAG Starting echo canceller calibration") + core.startEchoCancellerCalibration() + calibratedEchoCancellerValue.postValue( + AppUtils.getString(R.string.settings_calls_calibrate_echo_canceller_in_progress) + ) + } + } + + @UiThread + fun toggleAdaptiveRateControl() { + val newValue = adaptiveRateControlEnabled.value == false + coreContext.postOnCoreThread { core -> + core.isAdaptiveRateControlEnabled = newValue + adaptiveRateControlEnabled.postValue(newValue) + } + } + @UiThread fun toggleEnableVideo() { val newValue = videoEnabled.value == false @@ -697,4 +747,25 @@ class SettingsViewModel @UiThread constructor() : GenericViewModel() { } videoCodecs.postValue(videoCodecsList) } + + @WorkerThread + private fun echoCancellerCalibrationFinished(status: EcCalibratorStatus, delay: Int) { + val value = when (status) { + EcCalibratorStatus.DoneNoEcho -> { + echoCancellerEnabled.postValue(false) + AppUtils.getString(R.string.settings_calls_calibrate_echo_canceller_done_no_echo) + } + EcCalibratorStatus.Done -> { + echoCancellerEnabled.postValue(true) + AppUtils.getString(R.string.settings_calls_calibrate_echo_canceller_done).format( + delay + ) + } + EcCalibratorStatus.Failed -> { + AppUtils.getString(R.string.settings_calls_calibrate_echo_canceller_failed) + } + else -> "" + } + calibratedEchoCancellerValue.postValue(value) + } } diff --git a/app/src/main/res/layout/settings_calls.xml b/app/src/main/res/layout/settings_calls.xml index 3f803b37e..4ad7de5d3 100644 --- a/app/src/main/res/layout/settings_calls.xml +++ b/app/src/main/res/layout/settings_calls.xml @@ -58,6 +58,65 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + + app:layout_constraintTop_toBottomOf="@id/adaptive_rate_control_switch" /> Attention, vous ne pourrez pas revenir en arrière ! Empêcher l\'interface d\'être enregistrée Appels - Utiliser l\'annulateur d\'écho - Évite que de l\'écho soit entendu par votre correspondant + Utiliser l\'annulateur d\'écho logiciel + Évite que de l\'écho soit entendu par votre correspondant si un annulateur matériel n\'est pas disponible + Calibrer l\'annulateur d\'écho + en cours + pas d\'écho + %s ms + échec + Contrôle qualité adaptatif Activer la vidéo Activer la FEC vidéo Vibrer lors de la réception d\'un appel diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f60d307b5..13c8e712d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -216,8 +216,14 @@ Warning: once enabled it can\'t be disabled! Prevent interface from being recorded Calls - Use echo canceller - Prevents echo from being heard by remote end + Use software echo canceller + Prevents echo from being heard by remote end if no hardware echo canceller is available + Calibrate echo canceller + in progress + no echo + %s ms + failed + Adaptive rate control Enable video Enable video FEC Vibrate while incoming call is ringing