From 111fef6603a1b940692a004678d122168bc19ebc Mon Sep 17 00:00:00 2001 From: Benoit Martins Date: Wed, 3 Jan 2024 16:34:04 +0100 Subject: [PATCH] Edit audio route and add an audio reminder --- Linphone/Localizable.xcstrings | 3 + Linphone/UI/Call/CallView.swift | 40 ++++------- .../UI/Call/ViewModel/CallViewModel.swift | 66 ++++--------------- 3 files changed, 30 insertions(+), 79 deletions(-) diff --git a/Linphone/Localizable.xcstrings b/Linphone/Localizable.xcstrings index b5524e746..467b2feee 100644 --- a/Linphone/Localizable.xcstrings +++ b/Linphone/Localizable.xcstrings @@ -316,6 +316,9 @@ }, "First name*" : { + }, + "Headphones" : { + }, "History has been deleted" : { diff --git a/Linphone/UI/Call/CallView.swift b/Linphone/UI/Call/CallView.swift index 937595fc3..b9d952974 100644 --- a/Linphone/UI/Call/CallView.swift +++ b/Linphone/UI/Call/CallView.swift @@ -36,7 +36,6 @@ struct CallView: View { let pub = NotificationCenter.default.publisher(for: AVAudioSession.routeChangeNotification) @State var startDate = Date.now - @State var audioRouteIsSpeaker: Bool = false @State var audioRouteSheet: Bool = false @State var hideButtonsSheet: Bool = false @State var options: Int = 1 @@ -96,10 +95,6 @@ struct CallView: View { .cornerRadius(40) Button { - options = callViewModel.getAudioRoute() - print("audioRouteIsSpeakeraudioRouteIsSpeaker output \(AVAudioSession.sharedInstance().currentRoute.outputs)") - print("audioRouteIsSpeakeraudioRouteIsSpeaker inputs \(AVAudioSession.sharedInstance().availableInputs?.count)") - if AVAudioSession.sharedInstance().availableInputs != nil && !AVAudioSession.sharedInstance().availableInputs!.filter({ $0.portType.rawValue.contains("Bluetooth") }).isEmpty { @@ -108,12 +103,9 @@ struct CallView: View { DispatchQueue.global().asyncAfter(deadline: .now() + 0.5) { audioRouteSheet = true } - } else { - audioRouteIsSpeaker = !audioRouteIsSpeaker - do { - try AVAudioSession.sharedInstance().overrideOutputAudioPort(audioRouteIsSpeaker ? .speaker : .none) + try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSession.sharedInstance().currentRoute.outputs.filter({ $0.portType.rawValue == "Speaker" }).isEmpty ? .speaker : .none) } catch _ { } @@ -310,17 +302,17 @@ struct CallView: View { audioRouteSheet = false hideButtonsSheet = false }) { - VStack(spacing: 0) { Button(action: { options = 1 - audioRouteIsSpeaker = false - do { - try AVAudioSession.sharedInstance().overrideOutputAudioPort(audioRouteIsSpeaker ? .speaker : .none) - try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .voiceChat, options: .defaultToSpeaker) - try AVAudioSession.sharedInstance().setActive(true) + try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none) + if callViewModel.isHeadPhoneAvailable() { + try AVAudioSession.sharedInstance().setPreferredInput(AVAudioSession.sharedInstance().availableInputs?.filter({ $0.portType.rawValue.contains("Receiver") }).first) + } else { + try AVAudioSession.sharedInstance().setPreferredInput(AVAudioSession.sharedInstance().availableInputs?.first) + } } catch _ { } @@ -332,12 +324,12 @@ struct CallView: View { .foregroundStyle(.white) .frame(width: 25, height: 25, alignment: .leading) - Text("Earpiece") + Text(!callViewModel.isHeadPhoneAvailable() ? "Earpiece" : "Headphones") .default_text_style_white(styleSize: 15) Spacer() - Image("ear") + Image(!callViewModel.isHeadPhoneAvailable() ? "ear" : "headset") .renderingMode(.template) .resizable() .foregroundStyle(.white) @@ -349,10 +341,8 @@ struct CallView: View { Button(action: { options = 2 - audioRouteIsSpeaker = true - do { - try AVAudioSession.sharedInstance().overrideOutputAudioPort(audioRouteIsSpeaker ? .speaker : .none) + try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker) } catch _ { } @@ -381,12 +371,9 @@ struct CallView: View { Button(action: { options = 3 - audioRouteIsSpeaker = false - do { - try AVAudioSession.sharedInstance().overrideOutputAudioPort(audioRouteIsSpeaker ? .speaker : .none) - try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .voiceChat, options: .allowBluetooth) - try AVAudioSession.sharedInstance().setActive(true) + try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none) + try AVAudioSession.sharedInstance().setPreferredInput(AVAudioSession.sharedInstance().availableInputs?.filter({ $0.portType.rawValue.contains("Bluetooth") }).first) } catch _ { } @@ -653,12 +640,11 @@ struct CallView: View { } func getAudioRouteImage() { - print("getAudioRouteImagegetAudioRouteImage") imageAudioRoute = AVAudioSession.sharedInstance().currentRoute.outputs.filter({ $0.portType.rawValue == "Speaker" }).isEmpty ? ( AVAudioSession.sharedInstance().currentRoute.outputs.filter({ $0.portType.rawValue.contains("Bluetooth") }).isEmpty ? ( - AVAudioSession.sharedInstance().currentRoute.outputs.filter({ $0.portType.rawValue == "Receiver" }).isEmpty + callViewModel.isHeadPhoneAvailable() ? "headset" : "speaker-slash" ) diff --git a/Linphone/UI/Call/ViewModel/CallViewModel.swift b/Linphone/UI/Call/ViewModel/CallViewModel.swift index c7ad9cca7..1cf74ad54 100644 --- a/Linphone/UI/Call/ViewModel/CallViewModel.swift +++ b/Linphone/UI/Call/ViewModel/CallViewModel.swift @@ -38,7 +38,14 @@ class CallViewModel: ObservableObject { let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() init() { - setupNotifications() + + do { + try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .voiceChat, options: .allowBluetooth) + try AVAudioSession.sharedInstance().setActive(true) + } catch _ { + + } + coreContext.doOnCoreQueue { core in if core.currentCall != nil && core.currentCall!.remoteAddress != nil { DispatchQueue.main.async { @@ -113,59 +120,14 @@ class CallViewModel: ObservableObject { } } - func setupNotifications() { - /* - notifCenter.addObserver(self, - selector: #selector(handleRouteChange), - name: AVAudioSession.routeChangeNotification, - object: nil) - */ - - //NotificationCenter.default.addObserver(self, selector: Selector(("handleRouteChange")), name: UITextView.textDidChangeNotification, object: nil) - } - - - func handleRouteChange(notification: Notification) { - guard let userInfo = notification.userInfo, - let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt, - let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else { - return - } - - // Switch over the route change reason. - switch reason { - - - case .newDeviceAvailable, .oldDeviceUnavailable: // New device found. - print("handleRouteChangehandleRouteChange handleRouteChange") - - AVAudioSession.sharedInstance().currentRoute.outputs.filter({ $0.portType.rawValue == "Speaker" }).isEmpty - ? ( - AVAudioSession.sharedInstance().currentRoute.outputs.filter({ $0.portType.rawValue.contains("Bluetooth") }).isEmpty - ? ( - AVAudioSession.sharedInstance().currentRoute.outputs.filter({ $0.portType.rawValue == "Receiver" }).isEmpty - ? "headset" - : "speaker-slash" - ) - : "bluetooth" - ) - : "speaker-high" - - /* - case .oldDeviceUnavailable: // Old device removed. - if let previousRoute = - userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription { - + func isHeadPhoneAvailable() -> Bool { + guard let availableInputs = AVAudioSession.sharedInstance().availableInputs else {return false} + for inputDevice in availableInputs { + if inputDevice.portType == .headsetMic || inputDevice.portType == .headphones { + return true } - */ - default: () } - } - - - func hasHeadphones(in routeDescription: AVAudioSessionRouteDescription) -> Bool { - // Filter the outputs to only those with a port type of headphones. - return !routeDescription.outputs.filter({$0.portType == .headphones}).isEmpty + return false } func getAudioRoute() -> Int {