audio: fix speaker switch

Change-Id: I45ef4c1da798aab9039bffaa33219b40d86e4537
diff --git a/Ring/Ring/Calls/ButtonsContainerView.swift b/Ring/Ring/Calls/ButtonsContainerView.swift
index c994f0e..d2dd38b 100644
--- a/Ring/Ring/Calls/ButtonsContainerView.swift
+++ b/Ring/Ring/Calls/ButtonsContainerView.swift
@@ -172,7 +172,7 @@
         if switchSpeakerButton.isEnabled && !switchSpeakerButton.isHidden {
             self.optionsWithSpeaker()
         } else if !switchSpeakerButton.isHidden {
-            self.optionsWithSpeaker()
+            self.optionsWithoutSpeaker()
         }
     }
 
diff --git a/Ring/Ring/Calls/CallViewModel.swift b/Ring/Ring/Calls/CallViewModel.swift
index 4c3521b..299fc44 100644
--- a/Ring/Ring/Calls/CallViewModel.swift
+++ b/Ring/Ring/Calls/CallViewModel.swift
@@ -405,7 +405,13 @@
             .filter({ serviceEvent in
                 serviceEvent.eventType == .audioActivated
             }).subscribe(onNext: { [weak self] _ in
-                self?.audioService.startAudio()
+                guard let self = self else {return}
+                self.audioService.startAudio()
+                //for outgoing calls ve create audio sesion with default parameters.
+                //for incoming call audio session is created, ve need to override it
+                let overrideOutput = self.call?.callTypeValue == CallType.incoming.rawValue
+                self.audioService.setDefaultOutput(toSpeaker: !self.isAudioOnly,
+                                                   override: overrideOutput)
             }).disposed(by: self.disposeBag)
     }
 
@@ -433,22 +439,12 @@
                 }
             }
         }
-        self.callService.hangUpCallOrConference(callId: rendererId)
-            .subscribe(onCompleted: { [weak self] in
-                // switch to either spk or headset (if connected) for loud ringtone
-                // incase we were using rcv during the call
-                self?.videoService.stopAudioDevice()
-                self?.log.info("Call canceled")
-                }, onError: { [weak self] error in
-                    self?.log.error("Failed to cancel the call")
-            }).disposed(by: self.disposeBag)
+        self.callService
+            .hangUpCallOrConference(callId: rendererId)
+            .subscribe().disposed(by: self.disposeBag)
     }
 
     func answerCall() -> Completable {
-        if !self.audioService.isHeadsetConnected.value {
-            isAudioOnly ?
-                self.audioService.overrideToReceiver() : self.audioService.overrideToSpeaker()
-        }
         return self.callService.accept(call: call)
     }
 
@@ -456,10 +452,6 @@
         guard let account = self.accountService.currentAccount else {
             return
         }
-        if !self.audioService.isHeadsetConnected.value {
-            isAudioOnly ?
-                self.audioService.overrideToReceiver() : self.audioService.overrideToSpeaker()
-        }
         self.callService.placeCall(withAccount: account,
                                    toRingId: uri,
                                    userName: userName,
diff --git a/Ring/Ring/Services/AudioService.swift b/Ring/Ring/Services/AudioService.swift
index d18d96e..fe1caf8 100644
--- a/Ring/Ring/Services/AudioService.swift
+++ b/Ring/Ring/Services/AudioService.swift
@@ -44,6 +44,9 @@
 
     init(withAudioAdapter audioAdapter: AudioAdapter) {
         self.audioAdapter = audioAdapter
+        let bluetoothConnected = bluetoothAudioConnected()
+        let headphonesConnected = headphoneAudioConnected()
+        isHeadsetConnected.value = bluetoothConnected || headphonesConnected
 
         // Listen for audio route changes
         NotificationCenter.default.addObserver(
@@ -53,35 +56,31 @@
             object: nil)
     }
 
-    // swiftlint:disable force_cast
     @objc private func audioRouteChangeListener(_ notification: Notification) {
-        let reasonRaw = notification.userInfo![AVAudioSessionRouteChangeReasonKey] as! UInt
-        self.log.debug("Audio route change: \(reasonRaw)")
-        guard let reason = AVAudioSession.RouteChangeReason(rawValue: reasonRaw) else {
-            return
+        guard let userInfo = notification.userInfo,
+            let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt else {
+                return
         }
-        overrideAudioRoute(reason)
+        guard let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue),
+            (reason == .newDeviceAvailable || reason == .oldDeviceUnavailable || reason == .categoryChange) else {
+                return
+        }
+        overrideAudioRoute()
     }
-    // swiftlint:enable force_cast
 
-    func overrideAudioRoute(_ reason: AVAudioSession.RouteChangeReason) {
-        let wasHeadsetConnected = isHeadsetConnected.value
+    func overrideAudioRoute() {
         let bluetoothConnected = bluetoothAudioConnected()
         let headphonesConnected = headphoneAudioConnected()
-        self.log.debug("Audio route override - reason: \(reason.rawValue), status: bluetooth: \(bluetoothConnected), headphones: \(headphonesConnected)")
         isHeadsetConnected.value = bluetoothConnected || headphonesConnected
-        if reason == .override && !isHeadsetConnected.value {
-            setAudioOutputDevice(port: OutputPortType.builtinspk)
-        } else if wasHeadsetConnected != isHeadsetConnected.value {
-            if bluetoothConnected {
-                setAudioOutputDevice(port: OutputPortType.bluetooth)
-            } else if headphonesConnected {
-                setAudioOutputDevice(port: OutputPortType.headphones)
-            } else if wasHeadsetConnected {
-                let outputPort = isOutputToSpeaker.value ? OutputPortType.builtinspk : OutputPortType.receiver
-                setAudioOutputDevice(port: outputPort)
-            }
+        if bluetoothConnected {
+            setAudioOutputDevice(port: OutputPortType.bluetooth)
+            return
+        } else if headphonesConnected {
+            setAudioOutputDevice(port: OutputPortType.headphones)
+            return
         }
+        let outputPort = isOutputToSpeaker.value ? OutputPortType.builtinspk : OutputPortType.receiver
+        setAudioOutputDevice(port: outputPort)
     }
 
     func switchSpeaker() {
@@ -111,6 +110,13 @@
         setAudioOutputDevice(port: OutputPortType.receiver)
     }
 
+    func setDefaultOutput(toSpeaker: Bool, override: Bool = false) {
+        isOutputToSpeaker.value = toSpeaker
+        if override {
+            overrideAudioRoute()
+        }
+    }
+
     func bluetoothAudioConnected() -> Bool {
         let outputs = AVAudioSession.sharedInstance().currentRoute.outputs
         for output in outputs {