From 03f1bbca62b5c406aac56e5eaf7ed77b39236518 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 13 Jul 2017 15:37:01 -0400 Subject: [PATCH] Move state from CallViewController -> Call I think whenever reasonable we prefer to consodlidate state on the call // FREEBIE --- .../ViewControllers/CallViewController.swift | 34 +++++-------------- Signal/src/call/CallAudioService.swift | 11 +++++- Signal/src/call/CallService.swift | 2 +- Signal/src/call/SignalCall.swift | 17 +++++++--- .../call/UserInterface/CallUIAdapter.swift | 8 ++--- 5 files changed, 35 insertions(+), 37 deletions(-) diff --git a/Signal/src/ViewControllers/CallViewController.swift b/Signal/src/ViewControllers/CallViewController.swift index b4394695f..a7d1b4ddd 100644 --- a/Signal/src/ViewControllers/CallViewController.swift +++ b/Signal/src/ViewControllers/CallViewController.swift @@ -119,26 +119,6 @@ class CallViewController: UIViewController, CallObserver, CallServiceObserver, R } } - var audioSource: AudioSource? { - didSet { - if audioSource != oldValue { - if let audioSource = audioSource { - if audioSource.isBuiltInSpeaker { - // TODO seems like CVC knows too much about AudioSource. - // Maybe these conditionals belong in the callUIAdapter? Or audioService? - // self.callUIAdapter.audioService.setPreferredInput(audioSource: audioSource) - - self.callUIAdapter.setIsSpeakerphoneEnabled(call: self.call, isEnabled: true) - return - } - } - - self.callUIAdapter.setIsSpeakerphoneEnabled(call: self.call, isEnabled: false) - self.callUIAdapter.audioService.setPreferredInput(call: self.call, audioSource: audioSource) - } - } - } - // MARK: Initializers required init?(coder aDecoder: NSCoder) { @@ -390,11 +370,8 @@ class CallViewController: UIViewController, CallObserver, CallServiceObserver, R let currentAudioSource = callUIAdapter.audioService.currentAudioSource(call: self.call) for audioSource in self.appropriateAudioSources { - // TODO add image let routeAudioAction = UIAlertAction(title: audioSource.localizedName, style: .default) { _ in - // Disable any speakerphone - // TODO will this update the UI appropriately? - self.audioSource = audioSource + self.callUIAdapter.setAudioSource(call: self.call, audioSource: audioSource) } // HACK: private API to create checkmark for active audio source. @@ -879,7 +856,12 @@ class CallViewController: UIViewController, CallObserver, CallServiceObserver, R Logger.info("\(TAG) called \(#function)") button.isSelected = !button.isSelected if let call = self.call { - callUIAdapter.setIsSpeakerphoneEnabled(call: call, isEnabled: button.isSelected) + if button.isSelected { + callUIAdapter.setAudioSource(call: call, audioSource: AudioSource.builtInSpeaker) + } else { + // use default audio source + callUIAdapter.setAudioSource(call: call, audioSource: nil) + } } else { Logger.warn("\(TAG) pressed mute, but call was unexpectedly nil") } @@ -993,7 +975,7 @@ class CallViewController: UIViewController, CallObserver, CallServiceObserver, R self.updateCallUI(callState: call.state) } - internal func speakerphoneDidChange(call: SignalCall, isEnabled: Bool) { + internal func audioSourceDidChange(call: SignalCall, audioSource: AudioSource?) { AssertIsOnMainThread() self.updateCallUI(callState: call.state) } diff --git a/Signal/src/call/CallAudioService.swift b/Signal/src/call/CallAudioService.swift index 8fab5723e..5a752442c 100644 --- a/Signal/src/call/CallAudioService.swift +++ b/Signal/src/call/CallAudioService.swift @@ -139,10 +139,19 @@ struct AudioSource: Hashable { Logger.verbose("\(TAG) in \(#function) is no-op") } - internal func speakerphoneDidChange(call: SignalCall, isEnabled: Bool) { + internal func audioSourceDidChange(call: SignalCall, audioSource: AudioSource?) { AssertIsOnMainThread() ensureProperAudioSession(call: call) + + // It's importent to set preferred input *after* ensuring properAudioSession + // because some sources are only valid for certain categories. + let session = AVAudioSession.sharedInstance() + do { + try session.setPreferredInput(audioSource?.portDescription) + } catch { + owsFail("\(TAG) setPreferredInput in \(#function) failed with error: \(error)") + } } internal func hasLocalVideoDidChange(call: SignalCall, hasLocalVideo: Bool) { diff --git a/Signal/src/call/CallService.swift b/Signal/src/call/CallService.swift index 5dfc2b572..86dbc6c0e 100644 --- a/Signal/src/call/CallService.swift +++ b/Signal/src/call/CallService.swift @@ -1442,7 +1442,7 @@ protocol CallServiceObserver: class { // Do nothing } - internal func speakerphoneDidChange(call: SignalCall, isEnabled: Bool) { + internal func audioSourceDidChange(call: SignalCall, audioSource: AudioSource?) { AssertIsOnMainThread() // Do nothing } diff --git a/Signal/src/call/SignalCall.swift b/Signal/src/call/SignalCall.swift index 82a7cd44c..908291d12 100644 --- a/Signal/src/call/SignalCall.swift +++ b/Signal/src/call/SignalCall.swift @@ -26,7 +26,7 @@ protocol CallObserver: class { func stateDidChange(call: SignalCall, state: CallState) func hasLocalVideoDidChange(call: SignalCall, hasLocalVideo: Bool) func muteDidChange(call: SignalCall, isMuted: Bool) - func speakerphoneDidChange(call: SignalCall, isEnabled: Bool) + func audioSourceDidChange(call: SignalCall, audioSource: AudioSource?) } /** @@ -104,18 +104,25 @@ protocol CallObserver: class { } } - var isSpeakerphoneEnabled = false { + var audioSource: AudioSource? = nil { didSet { AssertIsOnMainThread() - - Logger.debug("\(TAG) isSpeakerphoneEnabled changed: \(oldValue) -> \(self.isSpeakerphoneEnabled)") + Logger.debug("\(TAG) audioSource changed: \(String(describing:oldValue)) -> \(String(describing: audioSource))") for observer in observers { - observer.value?.speakerphoneDidChange(call: self, isEnabled: isSpeakerphoneEnabled) + observer.value?.audioSourceDidChange(call: self, audioSource: audioSource) } } } + var isSpeakerphoneEnabled: Bool { + guard let audioSource = self.audioSource else { + return false + } + + return audioSource.isBuiltInSpeaker + } + var isOnHold = false var connectedDate: NSDate? diff --git a/Signal/src/call/UserInterface/CallUIAdapter.swift b/Signal/src/call/UserInterface/CallUIAdapter.swift index bf737b576..e47c287a0 100644 --- a/Signal/src/call/UserInterface/CallUIAdapter.swift +++ b/Signal/src/call/UserInterface/CallUIAdapter.swift @@ -207,13 +207,13 @@ extension CallUIAdaptee { adaptee.setHasLocalVideo(call: call, hasLocalVideo: hasLocalVideo) } - internal func setIsSpeakerphoneEnabled(call: SignalCall, isEnabled: Bool) { + internal func setAudioSource(call: SignalCall, audioSource: AudioSource?) { AssertIsOnMainThread() - // Speakerphone is not handled by CallKit (e.g. there is no CXAction), so we handle it w/o going through the - // adaptee, relying on the AudioService CallObserver to put the system in a state consistent with the call's + // AudioSource is not handled by CallKit (e.g. there is no CXAction), so we handle it w/o going through the + // adaptee, relying on the AudioService CallObserver to put the system in a state consistent with the call's // assigned property. - call.isSpeakerphoneEnabled = isEnabled + call.audioSource = audioSource } // CallKit handles ringing state on it's own. But for non-call kit we trigger ringing start/stop manually.