diff --git a/Ring/Ring/Calls/ButtonsContainerView.swift b/Ring/Ring/Calls/ButtonsContainerView.swift index c994f0ec294557b1c318350107d6df7d38d9853c..d2dd38b62a5fa3cfcfa4ccadb503b501c44ba97a 100644 --- a/Ring/Ring/Calls/ButtonsContainerView.swift +++ b/Ring/Ring/Calls/ButtonsContainerView.swift @@ -172,7 +172,7 @@ class ButtonsContainerView: UIView, NibLoadable { 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 4c3521bbf4d73ef3c2a4088bc458c4e7b2968077..299fc44977c304058476f550c28bded23ede01fb 100644 --- a/Ring/Ring/Calls/CallViewModel.swift +++ b/Ring/Ring/Calls/CallViewModel.swift @@ -405,7 +405,13 @@ class CallViewModel: Stateable, ViewModel { .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 @@ class CallViewModel: Stateable, ViewModel { } } } - 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 @@ class CallViewModel: Stateable, ViewModel { 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 d18d96e48938e979990171c2f60957ecfe2a6a70..fe1caf82adbc7f93d98f54ff832e8b5927c66b26 100644 --- a/Ring/Ring/Services/AudioService.swift +++ b/Ring/Ring/Services/AudioService.swift @@ -44,6 +44,9 @@ class AudioService { 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 @@ class AudioService { 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 + } + guard let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue), + (reason == .newDeviceAvailable || reason == .oldDeviceUnavailable || reason == .categoryChange) else { + return } - overrideAudioRoute(reason) + 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 @@ class AudioService { 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 {