From 110ce27c91a9169d3489f480821b116041c411f3 Mon Sep 17 00:00:00 2001 From: Paul Kompfner Date: Wed, 15 Jan 2025 09:56:27 -0500 Subject: [PATCH] In the iOS SimpleChatbot demo, wire up live updates to the selected mic and available mics list. This is beneficial for a few reasons: - Live updates are nice! We can now more easily see what's going on when we connect or disconnect a mic. - Resolves an issue where the initial selected mic was not shown. - Let us see when the Pipecat client automatically switches to a new mic, like when one is connected. --- .../model/CallContainerModel.swift | 40 ++++++++++++++++--- .../views/settings/SettingsView.swift | 20 ++-------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/examples/simple-chatbot/client/ios/SimpleChatbot/model/CallContainerModel.swift b/examples/simple-chatbot/client/ios/SimpleChatbot/model/CallContainerModel.swift index e638f088c..4af6c506c 100644 --- a/examples/simple-chatbot/client/ios/SimpleChatbot/model/CallContainerModel.swift +++ b/examples/simple-chatbot/client/ios/SimpleChatbot/model/CallContainerModel.swift @@ -24,6 +24,16 @@ class CallContainerModel: ObservableObject { var rtviClientIOS: RTVIClient? + @Published var selectedMic: MediaDeviceId? = nil { + didSet { + guard let selectedMic else { return } // don't store nil + var settings = SettingsManager.getSettings() + settings.selectedMic = selectedMic.id + SettingsManager.updateSettings(settings: settings) + } + } + @Published var availableMics: [MediaDeviceInfo] = [] + init() { // Changing the log level RTVIClientIOS.setLogLevel(.warn) @@ -52,15 +62,19 @@ class CallContainerModel: ObservableObject { ) self.rtviClientIOS?.delegate = self self.rtviClientIOS?.start() { result in - if case .failure(let error) = result { + switch result { + case .failure(let error): self.showError(message: error.localizedDescription) self.rtviClientIOS = nil + case .success(): + // Apply initial mic preference + if let selectedMic = currentSettings.selectedMic { + self.selectMic(MediaDeviceId(id: selectedMic)) + } + // Populate available devices list + self.availableMics = self.rtviClientIOS?.getAllMics() ?? [] } } - // Selecting the mic based on the preferences - if let selectedMic = currentSettings.selectedMic { - self.rtviClientIOS?.updateMic(micId: MediaDeviceId(id:selectedMic), completion: nil) - } self.saveCredentials(backendURL: baseUrl) } @@ -114,6 +128,11 @@ class CallContainerModel: ObservableObject { SettingsManager.updateSettings(settings: currentSettings) } + @MainActor + func selectMic(_ mic: MediaDeviceId) { + self.selectedMic = mic + self.rtviClientIOS?.updateMic(micId: mic, completion: nil) + } } extension CallContainerModel:RTVIClientDelegate, LLMHelperDelegate { @@ -196,4 +215,15 @@ extension CallContainerModel:RTVIClientDelegate, LLMHelperDelegate { } } + func onAvailableMicsUpdated(mics: [MediaDeviceInfo]) { + Task { @MainActor in + self.availableMics = mics + } + } + + func onMicUpdated(mic: MediaDeviceInfo?) { + Task { @MainActor in + self.selectedMic = mic?.id + } + } } diff --git a/examples/simple-chatbot/client/ios/SimpleChatbot/views/settings/SettingsView.swift b/examples/simple-chatbot/client/ios/SimpleChatbot/views/settings/SettingsView.swift index d161b2c55..194e24782 100644 --- a/examples/simple-chatbot/client/ios/SimpleChatbot/views/settings/SettingsView.swift +++ b/examples/simple-chatbot/client/ios/SimpleChatbot/views/settings/SettingsView.swift @@ -7,23 +7,21 @@ struct SettingsView: View { @Binding var showingSettings: Bool - @State private var selectedMic: MediaDeviceId? = nil @State private var isMicEnabled: Bool = true @State private var backendURL: String = "" var body: some View { - let microphones = self.model.rtviClientIOS?.getAllMics() ?? [] NavigationView { Form { Section(header: Text("Audio Settings")) { - List(microphones, id: \.self.id.id) { mic in + List(model.availableMics, id: \.self.id.id) { mic in Button(action: { - self.selectMic(mic.id) + model.selectMic(mic.id) }) { HStack { Text(mic.name) Spacer() - if mic.id == self.selectedMic { + if mic.id == model.selectedMic { Image(systemName: "checkmark") } } @@ -53,14 +51,9 @@ struct SettingsView: View { } } - private func selectMic(_ mic: MediaDeviceId) { - self.selectedMic = mic - self.model.rtviClientIOS?.updateMic(micId: mic, completion: nil) - } - private func saveSettings() { let newSettings = SettingsPreference( - selectedMic: selectedMic?.id, + selectedMic: model.selectedMic?.id, enableMic: isMicEnabled, backendURL: backendURL ) @@ -69,11 +62,6 @@ struct SettingsView: View { private func loadSettings() { let savedSettings = SettingsManager.getSettings() - if let selectedMic = savedSettings.selectedMic { - self.selectedMic = MediaDeviceId(id: selectedMic) - } else { - self.selectedMic = nil - } self.isMicEnabled = savedSettings.enableMic self.backendURL = savedSettings.backendURL }