From a1af408888ab0a4fc590ae46af9ff31a8f1ea5a7 Mon Sep 17 00:00:00 2001 From: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com> Date: Thu, 30 Apr 2020 21:10:16 -0400 Subject: [PATCH] audio: fix speaker switch Change-Id: I45ef4c1da798aab9039bffaa33219b40d86e4537 --- Ring/Ring/Calls/ButtonsContainerView.swift | 2 +- Ring/Ring/Calls/CallViewModel.swift | 28 +++++-------- Ring/Ring/Services/AudioService.swift | 48 ++++++++++++---------- 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/Ring/Ring/Calls/ButtonsContainerView.swift b/Ring/Ring/Calls/ButtonsContainerView.swift index c994f0ec2..d2dd38b62 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 4c3521bbf..299fc4497 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 d18d96e48..fe1caf82a 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 { -- GitLab