From bf64b496c9fab2a650f538c7959beeeb93698510 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 20 May 2024 10:16:49 +0200 Subject: [PATCH] Added audio & video codecs settings in advanced parameters --- .../ui/main/settings/model/CodecModel.kt | 53 ++++ .../settings/viewmodel/SettingsViewModel.kt | 61 ++++- .../res/layout/settings_advanced_fragment.xml | 253 +++++++++++++----- .../res/layout/settings_codec_list_cell.xml | 63 +++++ app/src/main/res/values-fr/strings.xml | 3 + app/src/main/res/values/strings.xml | 3 + 6 files changed, 362 insertions(+), 74 deletions(-) create mode 100644 app/src/main/java/org/linphone/ui/main/settings/model/CodecModel.kt create mode 100644 app/src/main/res/layout/settings_codec_list_cell.xml diff --git a/app/src/main/java/org/linphone/ui/main/settings/model/CodecModel.kt b/app/src/main/java/org/linphone/ui/main/settings/model/CodecModel.kt new file mode 100644 index 000000000..9ea8bb89f --- /dev/null +++ b/app/src/main/java/org/linphone/ui/main/settings/model/CodecModel.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This file is part of linphone-android + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.linphone.ui.main.settings.model + +import androidx.annotation.UiThread +import androidx.annotation.WorkerThread +import androidx.lifecycle.MutableLiveData + +class CodecModel @WorkerThread constructor( + val mimeType: String, + val clockRate: Int, + val recvFmtp: String?, + val isAudioCodec: Boolean, + enabled: Boolean, + val onEnabledChanged: ((enabled: Boolean) -> Unit) +) { + val isEnabled = MutableLiveData() + + val subtitle = MutableLiveData() + + init { + isEnabled.postValue(enabled) + if (isAudioCodec) { + subtitle.postValue("$clockRate Hz") + } else { + subtitle.postValue(recvFmtp.orEmpty()) + } + } + + @UiThread + fun toggleEnabled() { + val newValue = isEnabled.value == false + onEnabledChanged(newValue) + isEnabled.postValue(newValue) + } +} 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 5fafc1308..c03cf69f4 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 @@ -35,6 +35,7 @@ import org.linphone.core.VFS import org.linphone.core.tools.Log import org.linphone.ui.GenericViewModel import org.linphone.ui.main.settings.model.CardDavLdapModel +import org.linphone.ui.main.settings.model.CodecModel import org.linphone.utils.AppUtils import org.linphone.utils.Event @@ -152,14 +153,20 @@ class SettingsViewModel @UiThread constructor() : GenericViewModel() { val remoteProvisioningUrl = MutableLiveData() + val expandAudioDevices = MutableLiveData() val inputAudioDeviceIndex = MutableLiveData() val inputAudioDeviceLabels = arrayListOf() private val inputAudioDeviceValues = arrayListOf() - val outputAudioDeviceIndex = MutableLiveData() val outputAudioDeviceLabels = arrayListOf() private val outputAudioDeviceValues = arrayListOf() + val expandAudioCodecs = MutableLiveData() + val audioCodecs = MutableLiveData>() + + val expandVideoCodecs = MutableLiveData() + val videoCodecs = MutableLiveData>() + private val coreListener = object : CoreListenerStub() { override fun onAudioDevicesListUpdated(core: Core) { Log.i( @@ -188,6 +195,9 @@ class SettingsViewModel @UiThread constructor() : GenericViewModel() { expandMeetings.value = false expandNetwork.value = false expandUserInterface.value = false + expandAudioDevices.value = false + expandAudioCodecs.value = false + expandVideoCodecs.value = false isVfsEnabled.value = VFS.isEnabled(coreContext.context) @@ -222,6 +232,7 @@ class SettingsViewModel @UiThread constructor() : GenericViewModel() { remoteProvisioningUrl.postValue(core.provisioningUri) setupAudioDevices() + setupCodecs() } } @@ -497,6 +508,11 @@ class SettingsViewModel @UiThread constructor() : GenericViewModel() { } } + @UiThread + fun toggleAudioDevicesExpand() { + expandAudioDevices.value = expandAudioDevices.value == false + } + @UiThread fun setInputAudioDevice(index: Int) { coreContext.postOnCoreThread { core -> @@ -527,6 +543,8 @@ class SettingsViewModel @UiThread constructor() : GenericViewModel() { Log.i("$TAG Current default input audio device is [${defaultInputAudioDevice?.id}]") for (audioDevice in core.extendedAudioDevices) { if (audioDevice.hasCapability(AudioDevice.Capabilities.CapabilityRecord)) { + if (audioDevice.id.contains("deprecated")) continue + inputAudioDeviceLabels.add(audioDevice.id) inputAudioDeviceValues.add(audioDevice) if (audioDevice.id == defaultInputAudioDevice?.id) { @@ -541,6 +559,8 @@ class SettingsViewModel @UiThread constructor() : GenericViewModel() { Log.i("$TAG Current default output audio device is [${defaultOutputAudioDevice?.id}]") for (audioDevice in core.extendedAudioDevices) { if (audioDevice.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) { + if (audioDevice.id.contains("deprecated")) continue + outputAudioDeviceLabels.add(audioDevice.id) outputAudioDeviceValues.add(audioDevice) if (audioDevice.id == defaultOutputAudioDevice?.id) { @@ -550,4 +570,43 @@ class SettingsViewModel @UiThread constructor() : GenericViewModel() { } } } + + @UiThread + fun toggleAudioCodecsExpand() { + expandAudioCodecs.value = expandAudioCodecs.value == false + } + + @UiThread + fun toggleVideoCodecsExpand() { + expandVideoCodecs.value = expandVideoCodecs.value == false + } + + @WorkerThread + private fun setupCodecs() { + val core = coreContext.core + + val audioCodecsList = arrayListOf() + for (payload in core.audioPayloadTypes) { + val model = CodecModel( + payload.mimeType, + payload.clockRate, + null, + true, + payload.enabled() + ) { enabled -> + payload.enable(enabled) + } + audioCodecsList.add(model) + } + audioCodecs.postValue(audioCodecsList) + + val videoCodecsList = arrayListOf() + for (payload in core.videoPayloadTypes) { + val model = CodecModel(payload.mimeType, -1, payload.recvFmtp, false, payload.enabled()) { enabled -> + payload.enable(enabled) + } + videoCodecsList.add(model) + } + videoCodecs.postValue(videoCodecsList) + } } diff --git a/app/src/main/res/layout/settings_advanced_fragment.xml b/app/src/main/res/layout/settings_advanced_fragment.xml index 9fd5875c7..ba1d0bea3 100644 --- a/app/src/main/res/layout/settings_advanced_fragment.xml +++ b/app/src/main/res/layout/settings_advanced_fragment.xml @@ -141,92 +141,199 @@ app:layout_constraintTop_toBottomOf="@id/remote_provisioning"/> - - - - - - - + + + + + + + + + + + + + + + + + + - + + + android:layout_marginBottom="@dimen/screen_bottom_margin" + android:orientation="vertical" + android:paddingBottom="16dp" + android:background="@drawable/shape_squircle_white_background" + android:visibility="@{viewModel.expandVideoCodecs ? View.VISIBLE : View.GONE}" + entries="@{viewModel.videoCodecs}" + layout="@{@layout/settings_codec_list_cell}" + app:layout_constraintTop_toBottomOf="@id/video_codecs_title" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" /> diff --git a/app/src/main/res/layout/settings_codec_list_cell.xml b/app/src/main/res/layout/settings_codec_list_cell.xml new file mode 100644 index 000000000..e6f3d0f0e --- /dev/null +++ b/app/src/main/res/layout/settings_codec_list_cell.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index e9902f875..890157f35 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -278,8 +278,11 @@ Garder l\'app en vie via un Service URL de configuration distante Télécharger & appliquer + Périphériques audio Périphérique de capture par défaut Périphérique d\'écoute par défaut + Codecs audio + Codecs vidéo Votre compte diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1493ad15d..df9459c5c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -313,8 +313,11 @@ Keep app alive using Service Remote provisioning URL Download & apply + Audio devices Default input audio device Default output audio device + Audio codecs + Video codecs Manage account