From 88970c0e04ec27b3d62cc875bc162d9307a99537 Mon Sep 17 00:00:00 2001 From: QuentinArguillere Date: Mon, 10 May 2021 11:52:08 +0200 Subject: [PATCH] Replace bluetoothEnabled and speakerEnabled flags in the CallManager by isBluetoothEnabled and isSpeakerEnabled function, which will give real time state of the API based on what the linphone core getAudioDevice functions returns --- Classes/CallManager.swift | 67 ++++++++++------------------ Classes/CallOutgoingView.m | 4 +- Classes/CallView.m | 4 +- Classes/LinphoneManager.h | 1 - Classes/LinphoneManager.m | 61 ++++--------------------- Classes/LinphoneUI/UIPauseButton.m | 4 +- Classes/LinphoneUI/UISpeakerButton.m | 11 ++++- Classes/PhoneMainView.m | 2 +- Classes/ProviderDelegate.swift | 2 +- 9 files changed, 51 insertions(+), 105 deletions(-) diff --git a/Classes/CallManager.swift b/Classes/CallManager.swift index 85739737b..72c4889e9 100644 --- a/Classes/CallManager.swift +++ b/Classes/CallManager.swift @@ -39,8 +39,6 @@ import AVFoundation let callController: CXCallController! // to support callkit var lc: Core? @objc var speakerBeforePause : Bool = false - @objc var speakerEnabled : Bool = false - @objc var bluetoothEnabled : Bool = false @objc var nextCallIsTransfer: Bool = false @objc var alreadyRegisteredForNotification: Bool = false var referedFromCall: String? @@ -126,26 +124,8 @@ import AVFoundation #endif return false } - /* - @objc func allowSpeaker() -> Bool { - if (UIDevice.current.userInterfaceIdiom == .pad) { - // For now, ipad support only speaker. - return true - } - return true - var allow = true - let newRoute = AVAudioSession.sharedInstance().currentRoute - if (newRoute.outputs.count > 0) { - let route = newRoute.outputs[0].portType - allow = !( route == .lineOut || route == .headphones || (AudioHelper.bluetoothRoutes() as Array).contains(where: {($0 as! AVAudioSession.Port) == route})) - } - - return allow - } - */ @objc func changeRouteToSpeaker() { - speakerEnabled = true for device in lc!.audioDevices { if (device.type == AudioDeviceType.Speaker) { lc!.outputAudioDevice = device @@ -153,46 +133,46 @@ import AVFoundation } } UIDevice.current.isProximityMonitoringEnabled = false - bluetoothEnabled = false } @objc func changeRouteToBluetooth() { - bluetoothEnabled = true for device in lc!.audioDevices { if (device.type == AudioDeviceType.Bluetooth || device.type == AudioDeviceType.BluetoothA2DP) { lc!.outputAudioDevice = device break } } - speakerEnabled = false UIDevice.current.isProximityMonitoringEnabled = (lc!.callsNb > 0) } @objc func changeRouteToDefault() { - bluetoothEnabled = false - speakerEnabled = false lc!.outputAudioDevice = lc!.defaultOutputAudioDevice } - /* - @objc func enableSpeaker(enable: Bool) { - speakerEnabled = enable - do { - if (enable && allowSpeaker()) { - try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker) - UIDevice.current.isProximityMonitoringEnabled = false - bluetoothEnabled = false - } else { - try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none) - let buildinPort = AudioHelper.builtinAudioDevice() - try AVAudioSession.sharedInstance().setPreferredInput(buildinPort) - UIDevice.current.isProximityMonitoringEnabled = (lc!.callsNb > 0) + @objc func isBluetoothAvailable() -> Bool { + for device in lc!.audioDevices { + if (device.type == AudioDeviceType.Bluetooth || device.type == AudioDeviceType.BluetoothA2DP) { + let name = device.deviceName + return true; } - } catch { - Log.directLog(BCTBX_LOG_ERROR, text: "Failed to change audio route: err \(error)") } + return false; } -*/ + + @objc func isSpeakerEnabled() -> Bool { + if let outputDevice = lc!.outputAudioDevice { + return outputDevice.type == AudioDeviceType.Speaker + } + return false + } + + @objc func isBluetoothEnabled() -> Bool { + if let outputDevice = lc!.outputAudioDevice { + return (outputDevice.type == AudioDeviceType.Bluetooth || outputDevice.type == AudioDeviceType.BluetoothA2DP) + } + return false + } + func requestTransaction(_ transaction: CXTransaction, action: String) { callController.request(transaction) { error in if let error = error { @@ -575,7 +555,7 @@ import AVFoundation // disable this because I don't find anygood reason for it: _bluetoothAvailable = FALSE; // furthermore it introduces a bug when calling multiple times since route may not be // reconfigured between cause leading to bluetooth being disabled while it should not - CallManager.instance().bluetoothEnabled = false + //CallManager.instance().bluetoothEnabled = false } if UIApplication.shared.applicationState != .active && (callLog == nil || callLog?.status == .Missed || callLog?.status == .Aborted || callLog?.status == .EarlyAborted) { @@ -636,7 +616,8 @@ import AVFoundation } if (cstate == .IncomingReceived || cstate == .OutgoingInit || cstate == .Connected || cstate == .StreamsRunning) { - if ((call.currentParams?.videoEnabled ?? false) && !CallManager.speaker_already_enabled && !CallManager.instance().bluetoothEnabled) { + // if ((call.currentParams?.videoEnabled ?? false) && !CallManager.speaker_already_enabled && !CallManager.instance().bluetoothEnabled) { + if ((call.currentParams?.videoEnabled ?? false) && !CallManager.speaker_already_enabled && !CallManager.instance().isBluetoothEnabled()) { CallManager.instance().changeRouteToSpeaker() CallManager.speaker_already_enabled = true } diff --git a/Classes/CallOutgoingView.m b/Classes/CallOutgoingView.m index 10555ad92..c5057377d 100644 --- a/Classes/CallOutgoingView.m +++ b/Classes/CallOutgoingView.m @@ -185,8 +185,8 @@ static UICompositeViewDescription *compositeDescription = nil; [_routesButton setOn]; } - _routesBluetoothButton.selected = CallManager.instance.bluetoothEnabled; - _routesSpeakerButton.selected = CallManager.instance.speakerEnabled; + _routesBluetoothButton.selected = [CallManager.instance isBluetoothEnabled]; + _routesSpeakerButton.selected = [CallManager.instance isSpeakerEnabled]; _routesEarpieceButton.selected = !_routesBluetoothButton.selected && !_routesSpeakerButton.selected; if (hidden != _routesView.hidden) { diff --git a/Classes/CallView.m b/Classes/CallView.m index 739e0abe1..bf38ef65f 100644 --- a/Classes/CallView.m +++ b/Classes/CallView.m @@ -493,8 +493,8 @@ static void hideSpinner(LinphoneCall *call, void *user_data) { [_routesButton setOn]; } - _routesBluetoothButton.selected = CallManager.instance.bluetoothEnabled; - _routesSpeakerButton.selected = CallManager.instance.speakerEnabled; + _routesBluetoothButton.selected = [CallManager.instance isBluetoothEnabled]; + _routesSpeakerButton.selected = [CallManager.instance isSpeakerEnabled]; _routesEarpieceButton.selected = !_routesBluetoothButton.selected && !_routesSpeakerButton.selected; if (hidden != _routesView.hidden) { diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h index 98e4856c4..3244079c2 100644 --- a/Classes/LinphoneManager.h +++ b/Classes/LinphoneManager.h @@ -190,7 +190,6 @@ typedef struct _LinphoneManagerSounds { - (void)migrationPerAccount; - (void)setupGSMInteraction; -//- (void)setBluetoothEnabled:(BOOL)enable; - (BOOL)isCTCallCenterExist; @property (readonly) BOOL isTesting; diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 1eeccefbc..d2ac42af7 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -1732,58 +1732,15 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) { if (IPAD) return; - // there is at least one bug when you disconnect an audio bluetooth headset - // since we only get notification of route having changed, we cannot tell if that is due to: - // -bluetooth headset disconnected or - // -user wanted to use earpiece - // the only thing we can assume is that when we lost a device, it must be a bluetooth one (strong hypothesis though) - if ([[notif.userInfo valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue] == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) - _bluetoothAvailable = NO; - - AVAudioSessionRouteDescription *newRoute = [AVAudioSession sharedInstance].currentRoute; - - if (newRoute && newRoute.outputs.count > 0) { - NSString *route = newRoute.outputs[0].portType; - LOGI(@"Current audio route is [%s]", [route UTF8String]); - linphone_core_audio_route_changed(theLinphoneCore); - - CallManager.instance.speakerEnabled = [route isEqualToString:AVAudioSessionPortBuiltInSpeaker]; - if (([[AudioHelper bluetoothRoutes] containsObject:route]) && !CallManager.instance.speakerEnabled) { - _bluetoothAvailable = TRUE; - CallManager.instance.bluetoothEnabled = TRUE; - } else - CallManager.instance.bluetoothEnabled = FALSE; - - NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:_bluetoothAvailable], @"available", nil]; - [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneBluetoothAvailabilityUpdate - object:self - userInfo:dict]; - } + _bluetoothAvailable = [CallManager.instance isBluetoothAvailable]; + + NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:_bluetoothAvailable], @"available", nil]; + [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneBluetoothAvailabilityUpdate + object:self + userInfo:dict]; + } -/* -- (void)setBluetoothEnabled:(BOOL)enable { - if (_bluetoothAvailable) { - // The change of route will be done in enableSpeaker - CallManager.instance.bluetoothEnabled = enable; - if (CallManager.instance.bluetoothEnabled) { - NSError *err = nil; - AVAudioSessionPortDescription *_bluetoothPort = [AudioHelper bluetoothAudioDevice]; - [[AVAudioSession sharedInstance] setPreferredInput:_bluetoothPort error:&err]; - // if setting bluetooth failed, it must be because the device is not available - // anymore (disconnected), so deactivate bluetooth. - if (err) { - CallManager.instance.bluetoothEnabled = FALSE; - LOGE(@"Failed to enable bluetooth: err %@", err.localizedDescription); - err = nil; - } else { - CallManager.instance.speakerEnabled = FALSE; - return; - } - } - } - [CallManager.instance enableSpeakerWithEnable:CallManager.instance.speakerEnabled]; -} -*/ + #pragma mark - Call Functions - (void)send:(NSString *)replyText toChatRoom:(LinphoneChatRoom *)room { LinphoneChatMessage *msg = linphone_chat_room_create_message(room, replyText.UTF8String); @@ -2108,7 +2065,7 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) { if ([ct currentCalls] != nil) { if (call) { LOGI(@"Pausing SIP call because GSM call"); - CallManager.instance.speakerBeforePause = CallManager.instance.speakerEnabled; + CallManager.instance.speakerBeforePause = [CallManager.instance isSpeakerEnabled]; linphone_call_pause(call); [self startCallPausedLongRunningTask]; } else if (linphone_core_is_in_conference(theLinphoneCore)) { diff --git a/Classes/LinphoneUI/UIPauseButton.m b/Classes/LinphoneUI/UIPauseButton.m index 261352c9b..a6ea08d7c 100644 --- a/Classes/LinphoneUI/UIPauseButton.m +++ b/Classes/LinphoneUI/UIPauseButton.m @@ -85,7 +85,7 @@ if ([CallManager callKitEnabled]) { [CallManager.instance setHeldWithCall:call hold:true]; } else { - CallManager.instance.speakerBeforePause = CallManager.instance.speakerEnabled; + CallManager.instance.speakerBeforePause = [CallManager.instance isSpeakerEnabled]; linphone_call_pause(call); } } else { @@ -106,7 +106,7 @@ if ([CallManager callKitEnabled]) { [CallManager.instance setHeldWithCall:currentCall hold:true]; } else { - CallManager.instance.speakerBeforePause = CallManager.instance.speakerEnabled; + CallManager.instance.speakerBeforePause = [CallManager.instance isSpeakerEnabled]; linphone_call_pause(currentCall); } } else { diff --git a/Classes/LinphoneUI/UISpeakerButton.m b/Classes/LinphoneUI/UISpeakerButton.m index 8ba12c8de..64c12d5b9 100644 --- a/Classes/LinphoneUI/UISpeakerButton.m +++ b/Classes/LinphoneUI/UISpeakerButton.m @@ -34,6 +34,15 @@ INIT_WITH_COMMON_CF { return self; } +- (void)onOn { + [CallManager.instance changeRouteToSpeaker]; +} + +- (void)onOff { + [CallManager.instance changeRouteToDefault]; +} + + - (void)dealloc { [NSNotificationCenter.defaultCenter removeObserver:self]; } @@ -46,7 +55,7 @@ INIT_WITH_COMMON_CF { } - (bool)onUpdate { - return CallManager.instance.speakerEnabled; + return [CallManager.instance isSpeakerEnabled]; } @end diff --git a/Classes/PhoneMainView.m b/Classes/PhoneMainView.m index 4205e0eb3..7a74d0175 100644 --- a/Classes/PhoneMainView.m +++ b/Classes/PhoneMainView.m @@ -381,7 +381,7 @@ static RootViewManager *rootViewManagerInstance = nil; if (![LinphoneManager.instance isCTCallCenterExist]) { /*only register CT call center CB for connected call*/ [LinphoneManager.instance setupGSMInteraction]; - [[UIDevice currentDevice] setProximityMonitoringEnabled:!(CallManager.instance.speakerEnabled || CallManager.instance.bluetoothEnabled)]; + [[UIDevice currentDevice] setProximityMonitoringEnabled:!([CallManager.instance isSpeakerEnabled] || [CallManager.instance isBluetoothEnabled])]; } break; } diff --git a/Classes/ProviderDelegate.swift b/Classes/ProviderDelegate.swift index 81ada38b4..6526aec00 100644 --- a/Classes/ProviderDelegate.swift +++ b/Classes/ProviderDelegate.swift @@ -205,7 +205,7 @@ extension ProviderDelegate: CXProviderDelegate { if (call!.params?.localConferenceMode ?? false) { return } - CallManager.instance().speakerBeforePause = CallManager.instance().speakerEnabled + CallManager.instance().speakerBeforePause = CallManager.instance().isSpeakerEnabled() try call!.pause() } else { if (call?.conference != nil && CallManager.instance().lc?.callsNb ?? 0 > 1) {