diff --git a/Linphone.xcodeproj/project.pbxproj b/Linphone.xcodeproj/project.pbxproj index 3f72db35d..2ad99de6f 100644 --- a/Linphone.xcodeproj/project.pbxproj +++ b/Linphone.xcodeproj/project.pbxproj @@ -104,6 +104,7 @@ D732A9152B04C7FE00DB42BA /* HistoryListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D732A9142B04C7FE00DB42BA /* HistoryListViewModel.swift */; }; D732A91B2B061BD900DB42BA /* HistoryListBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D732A91A2B061BD900DB42BA /* HistoryListBottomSheet.swift */; }; D732C38C2D311D2500F78100 /* SettingsFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D732C38B2D311D2100F78100 /* SettingsFragment.swift */; }; + D7343FE82D3FA2000059D784 /* CodecModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7343FE72D3FA1F40059D784 /* CodecModel.swift */; }; D73449992BC6932A00778C56 /* MeetingWaitingRoomFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D73449982BC6932A00778C56 /* MeetingWaitingRoomFragment.swift */; }; D734499B2BC694C900778C56 /* MeetingWaitingRoomViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D734499A2BC694C900778C56 /* MeetingWaitingRoomViewModel.swift */; }; D748BF2C2ACD82D2004844EB /* ThirdPartySipAccountLoginFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D748BF2B2ACD82D2004844EB /* ThirdPartySipAccountLoginFragment.swift */; }; @@ -306,6 +307,7 @@ D732A9142B04C7FE00DB42BA /* HistoryListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryListViewModel.swift; sourceTree = ""; }; D732A91A2B061BD900DB42BA /* HistoryListBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryListBottomSheet.swift; sourceTree = ""; }; D732C38B2D311D2100F78100 /* SettingsFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsFragment.swift; sourceTree = ""; }; + D7343FE72D3FA1F40059D784 /* CodecModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodecModel.swift; sourceTree = ""; }; D73449982BC6932A00778C56 /* MeetingWaitingRoomFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingWaitingRoomFragment.swift; sourceTree = ""; }; D734499A2BC694C900778C56 /* MeetingWaitingRoomViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeetingWaitingRoomViewModel.swift; sourceTree = ""; }; D748BF2B2ACD82D2004844EB /* ThirdPartySipAccountLoginFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdPartySipAccountLoginFragment.swift; sourceTree = ""; }; @@ -952,6 +954,7 @@ D7DC096C2CFA193B00A6D47C /* Models */ = { isa = PBXGroup; children = ( + D7343FE72D3FA1F40059D784 /* CodecModel.swift */, ); path = Models; sourceTree = ""; @@ -1312,6 +1315,7 @@ D7DA67642ACCB31700E95002 /* ProfileModeFragment.swift in Sources */, D7CEE03D2B7A23B200FD79B7 /* ConversationsListFragment.swift in Sources */, D74C9CFC2ACACF370021626A /* WelcomePage3Fragment.swift in Sources */, + D7343FE82D3FA2000059D784 /* CodecModel.swift in Sources */, D77A080E2CB6BCAF0095D589 /* MessageConferenceInfo.swift in Sources */, C6A5A9412C10B5D50070FEA4 /* EncodableExtension.swift in Sources */, D719ABCC2ABC769C00B41C10 /* AssistantView.swift in Sources */, diff --git a/Linphone/UI/Main/Settings/Fragments/SettingsAdvancedFragment.swift b/Linphone/UI/Main/Settings/Fragments/SettingsAdvancedFragment.swift index e428f0b5d..fec853f2b 100644 --- a/Linphone/UI/Main/Settings/Fragments/SettingsAdvancedFragment.swift +++ b/Linphone/UI/Main/Settings/Fragments/SettingsAdvancedFragment.swift @@ -300,7 +300,7 @@ struct SettingsAdvancedFragment: View { .transition(.move(edge: .top)) } */ - /* + HStack(alignment: .center) { Text("settings_advanced_audio_codecs_title") .default_text_style_800(styleSize: 18) @@ -327,14 +327,14 @@ struct SettingsAdvancedFragment: View { if audioCodecsIsOpen { VStack(spacing: 0) { VStack(spacing: 30) { - Toggle("settings_calls_adaptive_rate_control_title", isOn: $settingsViewModel.adaptiveRateControl) - .default_text_style_700(styleSize: 15) - - Toggle("settings_calls_enable_video_title", isOn: $settingsViewModel.enableVideo) - .default_text_style_700(styleSize: 15) - - Toggle("settings_calls_auto_record_title", isOn: $settingsViewModel.autoRecord) - .default_text_style_700(styleSize: 15) + ForEach(settingsViewModel.audioCodecs) { audioCodec in + SettingsToggleWidget(title: audioCodec.mimeType, subtitle: audioCodec.subtitle, isOn: Binding( + get: { audioCodec.isEnabled }, + set: { newValue in + audioCodec.toggleEnabled() + } + )) + } } .padding(.vertical, 30) .padding(.horizontal, 20) @@ -372,8 +372,14 @@ struct SettingsAdvancedFragment: View { if videoCodecsIsOpen { VStack(spacing: 0) { VStack(spacing: 30) { - Toggle("settings_conversations_auto_download_title", isOn: $settingsViewModel.autoDownload) - .default_text_style_700(styleSize: 15) + ForEach(settingsViewModel.videoCodecs) { videoCodec in + SettingsToggleWidget(title: videoCodec.mimeType, subtitle: videoCodec.subtitle, isOn: Binding( + get: { videoCodec.isEnabled }, + set: { newValue in + videoCodec.toggleEnabled() + } + )) + } } .padding(.vertical, 30) .padding(.horizontal, 20) @@ -384,7 +390,6 @@ struct SettingsAdvancedFragment: View { .zIndex(-3) .transition(.move(edge: .top)) } - */ } } .background(Color.gray100) @@ -395,3 +400,29 @@ struct SettingsAdvancedFragment: View { .navigationBarHidden(true) } } + +struct SettingsToggleWidget: View { + var title: String + var subtitle: String + @Binding var isOn: Bool + + var body: some View { + HStack { + VStack(alignment: .leading, spacing: 2) { + Text(title) + .default_text_style_700(styleSize: 15) + if !subtitle.isEmpty { + Text(subtitle) + .foregroundColor(Color.grayMain2c500) + .default_text_style(styleSize: 14) + } + } + .layoutPriority(1) + + Toggle(isOn: $isOn) { + EmptyView() + } + .toggleStyle(SwitchToggleStyle()) + } + } +} diff --git a/Linphone/UI/Main/Settings/Models/CodecModel.swift b/Linphone/UI/Main/Settings/Models/CodecModel.swift new file mode 100644 index 000000000..d35bcd286 --- /dev/null +++ b/Linphone/UI/Main/Settings/Models/CodecModel.swift @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010-2023 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * 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 . + */ + +import Foundation + +class CodecModel: ObservableObject, Identifiable { + let id = UUID() + let mimeType: String + let clockRate: Int + let channels: Int + let recvFmtp: String? + let isAudioCodec: Bool + private let onEnabledChanged: (Bool) -> Void + + @Published var isEnabled: Bool + @Published var subtitle: String + + init( + mimeType: String, + clockRate: Int, + channels: Int, + recvFmtp: String?, + isAudioCodec: Bool, + enabled: Bool, + onEnabledChanged: @escaping (Bool) -> Void + ) { + self.mimeType = mimeType + self.clockRate = clockRate + self.channels = channels + self.recvFmtp = recvFmtp + self.isAudioCodec = isAudioCodec + self.isEnabled = enabled + self.onEnabledChanged = onEnabledChanged + + if isAudioCodec { + self.subtitle = "\(clockRate) Hz" + (isAudioCodec ? " (\(channels == 1 ? "Mono" : "Stereo"))" : "") + } else { + self.subtitle = recvFmtp ?? "" + } + } + + func toggleEnabled() { + let newValue = !isEnabled + onEnabledChanged(newValue) + isEnabled = newValue + } +} diff --git a/Linphone/UI/Main/Settings/ViewModel/SettingsViewModel.swift b/Linphone/UI/Main/Settings/ViewModel/SettingsViewModel.swift index 37b390d22..7ac6830d5 100644 --- a/Linphone/UI/Main/Settings/ViewModel/SettingsViewModel.swift +++ b/Linphone/UI/Main/Settings/ViewModel/SettingsViewModel.swift @@ -62,6 +62,9 @@ class SettingsViewModel: ObservableObject { @Published var outputAudioDeviceValues: [AudioDevice] = [] @Published var outputAudioDeviceIndex: Int = 0 + @Published var audioCodecs: [CodecModel] = [] + @Published var videoCodecs: [CodecModel] = [] + init() { CoreContext.shared.doOnCoreQueue { core in @@ -136,6 +139,8 @@ class SettingsViewModel: ObservableObject { ) core.addDelegate(delegate: self.coreDelegate!) */ + + self.setupCodecs() } } } @@ -249,6 +254,47 @@ class SettingsViewModel: ObservableObject { } } + func setupCodecs() { + CoreContext.shared.doOnCoreQueue { core in + var audioCodecsList: [CodecModel] = [] + for payload in core.audioPayloadTypes { + let model = CodecModel( + mimeType: payload.mimeType, + clockRate: payload.clockRate, + channels: payload.channels, + recvFmtp: nil, + isAudioCodec: true, + enabled: payload.enabled(), + onEnabledChanged: { enabled in + payload.enable(enabled: enabled) + } + ) + audioCodecsList.append(model) + } + + var videoCodecsList: [CodecModel] = [] + for payload in core.videoPayloadTypes { + let model = CodecModel( + mimeType: payload.mimeType, + clockRate: -1, + channels: -1, + recvFmtp: payload.recvFmtp, + isAudioCodec: false, + enabled: payload.enabled(), + onEnabledChanged: { enabled in + payload.enable(enabled: enabled) + } + ) + videoCodecsList.append(model) + } + + DispatchQueue.main.async { + self.audioCodecs = audioCodecsList + self.videoCodecs = videoCodecsList + } + } + } + func saveChangesWhenLeaving() { CoreContext.shared.doOnCoreQueue { core in if CorePreferences.vfsEnabled != self.enableVfs {