audio: fix audio switching
- Removes samplerate hack which fixed input but exposed requirement
for output downsampling in the event of an core layer samplerate
reduction. The audio session instance allows bluetooth after the
daemon initializes, allowing the input samplerate to be correctly
fetched.
- Sets the audio device to speakerphone or headset at app init and
when a call is terminated so the ringtone can be heard.
Change-Id: I99ebaca55dfd7295801626b8fa4f64ea24a5abb8
Reviewed-by: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
diff --git a/Ring/Ring/AppDelegate.swift b/Ring/Ring/AppDelegate.swift
index 18b6615..723ec99 100644
--- a/Ring/Ring/AppDelegate.swift
+++ b/Ring/Ring/AppDelegate.swift
@@ -89,6 +89,9 @@
SystemAdapter().registerConfigurationHandler()
self.startDaemon()
+ // sets output device to whatever is currently available (either spk / headset)
+ self.audioService.startAVAudioSession()
+
// disables hardware decoding
self.videoService.setDecodingAccelerated(withState: false)
@@ -106,9 +109,6 @@
})
.disposed(by: self.disposeBag)
- // set device to headset if present
- self.audioService.overrideAudioRoute(.override)
-
// themetize the app
Chameleon.setGlobalThemeUsingPrimaryColor(UIColor.ringMain, withSecondaryColor: UIColor.ringSecondary, andContentStyle: .light)
Chameleon.setRingThemeUsingPrimaryColor(UIColor.ringMain, withSecondaryColor: UIColor.ringSecondary, andContentStyle: .light)
diff --git a/Ring/Ring/Calls/CallViewModel.swift b/Ring/Ring/Calls/CallViewModel.swift
index 7ccf574..dc86025 100644
--- a/Ring/Ring/Calls/CallViewModel.swift
+++ b/Ring/Ring/Calls/CallViewModel.swift
@@ -293,6 +293,9 @@
}
self.callService.hangUp(callId: call.callId)
.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?.audioService.setToRing()
self?.log.info("Call canceled")
}, onError: { [weak self] error in
self?.log.error("Failed to cancel the call")
@@ -300,6 +303,10 @@
}
func answerCall() -> Completable {
+ // switch to rcv if that's what we were last using
+ if !self.audioService.isHeadsetConnected.value && !self.audioService.isOutputToSpeaker.value {
+ self.audioService.overrideToReceiver()
+ }
return self.callService.accept(call: call)
}
@@ -308,10 +315,9 @@
guard let account = self.accountService.currentAccount else {
return
}
- if isAudioOnly {
+ // switch to rcv if audio only and no headset connected
+ if isAudioOnly && !self.audioService.isHeadsetConnected.value {
self.audioService.overrideToReceiver()
- } else {
- self.audioService.overrideToSpeaker()
}
self.callService.placeCall(withAccount: account,
toRingId: uri,
diff --git a/Ring/Ring/Services/AudioService.swift b/Ring/Ring/Services/AudioService.swift
index 26d8522..a510d94 100644
--- a/Ring/Ring/Services/AudioService.swift
+++ b/Ring/Ring/Services/AudioService.swift
@@ -27,7 +27,6 @@
case bluetooth = 1
case headphones = 2
case receiver = 3
- case dummy = 4
}
class AudioService {
@@ -54,6 +53,18 @@
object: nil)
}
+ func startAVAudioSession() {
+ do {
+ try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord,
+ with: AVAudioSessionCategoryOptions.allowBluetooth)
+ try AVAudioSession.sharedInstance().setActive(true)
+ } catch {
+ log.error("\(error)")
+ }
+ setToRing()
+ }
+
+ // swiftlint:disable force_cast
@objc private func audioRouteChangeListener(_ notification: Notification) {
let reasonRaw = notification.userInfo![AVAudioSessionRouteChangeReasonKey] as! UInt
self.log.debug("Audio route change: \(reasonRaw)")
@@ -62,12 +73,13 @@
}
overrideAudioRoute(reason)
}
+ // swiftlint:enable force_cast
func overrideAudioRoute(_ reason: AVAudioSessionRouteChangeReason) {
let wasHeadsetConnected = isHeadsetConnected.value
let bluetoothConnected = bluetoothAudioConnected()
let headphonesConnected = headphoneAudioConnected()
- self.log.debug("Audio route status: bluetooth: \(bluetoothConnected), headphones: \(headphonesConnected)")
+ 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)
@@ -80,10 +92,6 @@
let outputPort = isOutputToSpeaker.value ? OutputPortType.builtinspk : OutputPortType.receiver
setAudioOutputDevice(port: outputPort)
}
- } else if reason == .categoryChange && (isHeadsetConnected.value || !isOutputToSpeaker.value) {
- // Hack switch to dummy device for first call using bluetooth/headset/receiver
- // allowing the samplerate for the input bus to be correctly set
- setAudioOutputDevice(port: OutputPortType.dummy)
}
}
@@ -98,6 +106,12 @@
}
}
+ func setToRing() {
+ if !isHeadsetConnected.value {
+ setAudioOutputDevice(port: OutputPortType.builtinspk)
+ }
+ }
+
func overrideToSpeaker() {
isOutputToSpeaker.value = true
setAudioOutputDevice(port: OutputPortType.builtinspk)
diff --git a/Ring/Ring/Services/CallsService.swift b/Ring/Ring/Services/CallsService.swift
index 3db93dc..177d958 100644
--- a/Ring/Ring/Services/CallsService.swift
+++ b/Ring/Ring/Services/CallsService.swift
@@ -253,7 +253,7 @@
let accountID = call?.accountId
self.sendVCard(callID: callId, accountID: accountID!)
}
-
+
//Emit the call to the observers
self.currentCall.onNext(call!)
}