Commit fdde0e12 authored by Andreas Traczyk's avatar Andreas Traczyk Committed by Kateryna Kostiuk

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's avatarKateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
parent 7898b758
......@@ -89,6 +89,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
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 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
})
.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)
......
......@@ -293,6 +293,9 @@ class CallViewModel: Stateable, ViewModel {
}
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 @@ class CallViewModel: Stateable, ViewModel {
}
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 @@ class CallViewModel: Stateable, ViewModel {
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,
......
......@@ -27,7 +27,6 @@ enum OutputPortType: Int {
case bluetooth = 1
case headphones = 2
case receiver = 3
case dummy = 4
}
class AudioService {
......@@ -54,6 +53,18 @@ class AudioService {
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 @@ class AudioService {
}
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 @@ class AudioService {
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 @@ class AudioService {
}
}
func setToRing() {
if !isHeadsetConnected.value {
setAudioOutputDevice(port: OutputPortType.builtinspk)
}
}
func overrideToSpeaker() {
isOutputToSpeaker.value = true
setAudioOutputDevice(port: OutputPortType.builtinspk)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment