From a51cb74f9b1ba7b78484ca19968a60895018e195 Mon Sep 17 00:00:00 2001 From: Ricardo Corrie Date: Thu, 31 Mar 2022 12:09:00 -0500 Subject: [PATCH 01/17] fix(ios): The getAudioRoutes changes the selected audio route #540 --- ios/RNCallKeep/RNCallKeep.m | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index eff7dc2c..04474b9c 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -505,6 +505,21 @@ + (void)setup:(NSDictionary *)options { } NSArray *ports = [RNCallKeep getAudioInputs]; + + BOOL isCategorySetted = [myAudioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:&err]; + if (!isCategorySetted) + { + NSLog(@"[RNCallKeep][setAudioRoute] setCategory failed"); + [NSException raise:@"setCategory failed" format:@"error: %@", err]; + } + + BOOL isCategoryActivated = [myAudioSession setActive:YES error:&err]; + if (!isCategoryActivated) + { + NSLog(@"[RNCallKeep][setAudioRoute] setActive failed"); + [NSException raise:@"setActive failed" format:@"error: %@", err]; + } + for (AVAudioSessionPortDescription *port in ports) { if ([port.portName isEqualToString:inputName]) { BOOL isSetted = [myAudioSession setPreferredInput:(AVAudioSessionPortDescription *)port error:&err]; @@ -570,20 +585,6 @@ + (NSArray *) getAudioInputs AVAudioSession* myAudioSession = [AVAudioSession sharedInstance]; - BOOL isCategorySetted = [myAudioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:&err]; - if (!isCategorySetted) - { - NSLog(@"[RNCallKeep][getAudioInputs] setCategory failed"); - [NSException raise:@"setCategory failed" format:@"error: %@", err]; - } - - BOOL isCategoryActivated = [myAudioSession setActive:YES error:&err]; - if (!isCategoryActivated) - { - NSLog(@"[RNCallKeep][getAudioInputs] setActive failed"); - [NSException raise:@"setActive failed" format:@"error: %@", err]; - } - NSArray *inputs = [myAudioSession availableInputs]; return inputs; } From 1df080f53b723addc46848967d4ef8ceca4b5cdd Mon Sep 17 00:00:00 2001 From: Ricardo Corrie Date: Mon, 29 Aug 2022 15:07:52 -0500 Subject: [PATCH 02/17] fix: [MOB-4845] Crashlytics: [__NSArray0 objectAtIndex:]: index 0 beyond bounds for empty NSArray --- ios/RNCallKeep/RNCallKeep.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index 04474b9c..289eebd5 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -178,7 +178,12 @@ + (void)initCallKitProvider { } + (NSString *) getAudioOutput { - return [AVAudioSession sharedInstance].currentRoute.outputs.count > 0 ? [AVAudioSession sharedInstance].currentRoute.outputs[0].portType : nil; + @try{ + return [AVAudioSession sharedInstance].currentRoute.outputs.count > 0 ? [AVAudioSession sharedInstance].currentRoute.outputs[0].portType : nil; + }@catch(NSException *e){ + NSLog(@"[RNCallKeep][getAudioOutput] exception: %@",e); + return nil; + } } + (void)setup:(NSDictionary *)options { From 9498a35767356e71727342f691a9d3b65813f43e Mon Sep 17 00:00:00 2001 From: Sasa Obadic Date: Thu, 13 Oct 2022 18:09:44 +0200 Subject: [PATCH 03/17] First fore bluetooth tryout commit. --- ios/RNCallKeep/RNCallKeep.h | 3 +++ ios/RNCallKeep/RNCallKeep.m | 47 +++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/ios/RNCallKeep/RNCallKeep.h b/ios/RNCallKeep/RNCallKeep.h index c8e7bbdf..da9fbb56 100644 --- a/ios/RNCallKeep/RNCallKeep.h +++ b/ios/RNCallKeep/RNCallKeep.h @@ -16,6 +16,9 @@ @interface RNCallKeep : RCTEventEmitter +@property(nonatomic,retain) NSTimer *forceBluetoothTimer; +@property BOOL shouldForceBluetooth; + @property (nonatomic, strong) CXCallController *callKeepCallController; @property (nonatomic, strong) CXProvider *callKeepProvider; diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index 289eebd5..5b180568 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -59,6 +59,7 @@ - (instancetype)init NSLog(@"[RNCallKeep][init]"); #endif if (self = [super init]) { + _shouldForceBluetooth = TRUE; _isStartCallActionEventListenerAdded = NO; _isReachable = NO; if (_delayedEvents == nil) _delayedEvents = [NSMutableArray array]; @@ -147,6 +148,12 @@ - (void)onAudioRouteChange:(NSNotification *)notification @"output": output, @"reason": @(reason), }]; + + if (_shouldForceBluetooth) { + // Force Bluetooth as soon as possible once onAudioRouteChange event handler finishes + _forceBluetoothTimer = [NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:@selector(forceBluetoothPreferredInput:) userInfo:nil repeats:YES]; + [_forceBluetoothTimer fire]; + } } - (void)sendEventWithNameWrapper:(NSString *)name body:(id)body { @@ -372,6 +379,9 @@ + (void)setup:(NSDictionary *)options { CXTransaction *transaction = [[CXTransaction alloc] initWithAction:endCallAction]; [self requestTransaction:transaction]; } + + // We are ready to force the Bluetooth for new calls + _shouldForceBluetooth = true; } RCT_EXPORT_METHOD(setOnHold:(NSString *)uuidString :(BOOL)shouldHold) @@ -502,6 +512,11 @@ + (void)setup:(NSDictionary *)options { AVAudioSession* myAudioSession = [AVAudioSession sharedInstance]; if ([inputName isEqualToString:@"Speaker"]) { BOOL isOverrided = [myAudioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&err]; + + if (isOverrided) { + _shouldForceBluetooth = FALSE; + } + if(!isOverrided){ [NSException raise:@"overrideOutputAudioPort failed" format:@"error: %@", err]; } @@ -528,6 +543,11 @@ + (void)setup:(NSDictionary *)options { for (AVAudioSessionPortDescription *port in ports) { if ([port.portName isEqualToString:inputName]) { BOOL isSetted = [myAudioSession setPreferredInput:(AVAudioSessionPortDescription *)port error:&err]; + + if (isSetted) { + _shouldForceBluetooth = FALSE; + } + if(!isSetted){ [NSException raise:@"setPreferredInput failed" format:@"error: %@", err]; } @@ -868,6 +888,33 @@ - (void)configureAudioSession [audioSession setActive:TRUE error:nil]; } +- (void) forceBluetoothPreferredInput:(id)sender +{ + [_forceBluetoothTimer invalidate]; + _forceBluetoothTimer = nil; + + AVAudioSession* audioSession = [AVAudioSession sharedInstance]; + NSArray *ports = [RNCallKeep getAudioInputs]; + + for (AVAudioSessionPortDescription *port in ports) { + if ([port.portType isEqualToString:AVAudioSessionPortBluetoothHFP] || + [port.portType isEqualToString:AVAudioSessionPortBluetoothA2DP]) { + @try { + NSError* err = nil; + BOOL isSetted = [audioSession setPreferredInput:(AVAudioSessionPortDescription *)port error:&err]; + + if (!isSetted) { + [NSException raise:@"forceBluetoothPreferredInput failed" format:@"error: %@", err]; + } + + break; + } @catch (NSException *e) { + NSLog(@"[RNCallKeep][forceBluetoothPreferredInput] exception: %@",e); + } + } + } +} + + (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options NS_AVAILABLE_IOS(9_0) From d6b763c702276ae540f586fe04a94eac99c128c9 Mon Sep 17 00:00:00 2001 From: Sasa Obadic Date: Fri, 14 Oct 2022 15:45:51 +0200 Subject: [PATCH 04/17] Additional flag fix if BT selected back as primary --- ios/RNCallKeep/RNCallKeep.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index 5b180568..c3e8e35a 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -545,7 +545,12 @@ + (void)setup:(NSDictionary *)options { BOOL isSetted = [myAudioSession setPreferredInput:(AVAudioSessionPortDescription *)port error:&err]; if (isSetted) { - _shouldForceBluetooth = FALSE; + if ([port.portType isEqualToString:AVAudioSessionPortBluetoothHFP] || + [port.portType isEqualToString:AVAudioSessionPortBluetoothA2DP]) { + _shouldForceBluetooth = TRUE; + } else { + _shouldForceBluetooth = FALSE; + } } if(!isSetted){ From fcd5e063604d4838d126d0817298de89f3d44324 Mon Sep 17 00:00:00 2001 From: Ricardo Corrie Date: Wed, 19 Oct 2022 08:48:19 -0500 Subject: [PATCH 05/17] Fixes audio routing issues on incoming calls when connected to BT --- ios/RNCallKeep/RNCallKeep.m | 48 +++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index 289eebd5..416821c5 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -511,7 +511,7 @@ + (void)setup:(NSDictionary *)options { NSArray *ports = [RNCallKeep getAudioInputs]; - BOOL isCategorySetted = [myAudioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:&err]; + BOOL isCategorySetted = [myAudioSession setCategory:AVAudioSessionCategoryPlayAndRecord mode:AVAudioSessionModeVoiceChat options: AVAudioSessionCategoryOptionAllowAirPlay | AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionAllowBluetoothA2DP error:&err]; if (!isCategorySetted) { NSLog(@"[RNCallKeep][setAudioRoute] setCategory failed"); @@ -854,18 +854,40 @@ - (void)configureAudioSession #ifdef DEBUG NSLog(@"[RNCallKeep][configureAudioSession] Activating audio session"); #endif - - AVAudioSession* audioSession = [AVAudioSession sharedInstance]; - [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil]; - - [audioSession setMode:AVAudioSessionModeDefault error:nil]; - - double sampleRate = 44100.0; - [audioSession setPreferredSampleRate:sampleRate error:nil]; - - NSTimeInterval bufferDuration = .005; - [audioSession setPreferredIOBufferDuration:bufferDuration error:nil]; - [audioSession setActive:TRUE error:nil]; + @try{ + NSError* err = nil; + + AVAudioSession* audioSession = [AVAudioSession sharedInstance]; + BOOL isConfigured = [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord mode:AVAudioSessionModeVoiceChat options: AVAudioSessionCategoryOptionAllowAirPlay | AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionAllowBluetoothA2DP error:&err]; + if(!isConfigured){ + NSLog(@"[RNCallKeep][configureAudioSession][setCategory] failed"); + [NSException raise:@"audioSession#setCategory failed" format:@"error: %@", err]; + } + + double sampleRate = 44100.0; + BOOL sampleRateSetted = [audioSession setPreferredSampleRate:sampleRate error:&err]; + if(!sampleRateSetted){ + NSLog(@"[RNCallKeep][configureAudioSession][setPreferredSampleRate] failed"); + [NSException raise:@"audioSession#setPreferredSampleRate failed" format:@"error: %@", err]; + } + + NSTimeInterval bufferDuration = .005; + BOOL bufferSetted = [audioSession setPreferredIOBufferDuration:bufferDuration error:&err]; + if(!bufferSetted){ + NSLog(@"[RNCallKeep][configureAudioSession][setPreferredIOBufferDuration] failed"); + [NSException raise:@"audioSession#setPreferredIOBufferDuration failed" format:@"error: %@", err]; + } + + BOOL isActivated = [audioSession setActive:TRUE error:&err]; + if(!isActivated){ + NSLog(@"[RNCallKeep][configureAudioSession][setActive] failed"); + [NSException raise:@"audioSession#setActive failed" format:@"error: %@", err]; + } + } + @catch ( NSException *e ){ + NSLog(@"[RNCallKeep][configureAudioSession] exception: %@",e); + } + } + (BOOL)application:(UIApplication *)application From dcc5158f2cadbf11c06d50134386fe1a1914157d Mon Sep 17 00:00:00 2001 From: Ricardo Corrie Date: Fri, 4 Nov 2022 13:01:17 -0500 Subject: [PATCH 06/17] Adds localbroadcastmanager support --- android/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/android/build.gradle b/android/build.gradle index 3accf1c6..5a9971bf 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -32,4 +32,5 @@ repositories { dependencies { implementation 'com.facebook.react:react-native:+' + implementation "androidx.localbroadcastmanager:localbroadcastmanager:1.1.0" } From 6965f4149451e8c145117254ccb97211e3029640 Mon Sep 17 00:00:00 2001 From: Ricardo Corrie Date: Fri, 4 Nov 2022 19:39:34 -0500 Subject: [PATCH 07/17] Revert "Adds localbroadcastmanager support" This reverts commit dcc5158f2cadbf11c06d50134386fe1a1914157d. --- android/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 5a9971bf..3accf1c6 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -32,5 +32,4 @@ repositories { dependencies { implementation 'com.facebook.react:react-native:+' - implementation "androidx.localbroadcastmanager:localbroadcastmanager:1.1.0" } From a2ca441754b2e93902bda8a38fb826efb6554378 Mon Sep 17 00:00:00 2001 From: Ricardo Corrie Date: Fri, 4 Nov 2022 19:40:07 -0500 Subject: [PATCH 08/17] Sets fixed RN version --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 3accf1c6..2e7b48a7 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -31,5 +31,5 @@ repositories { } dependencies { - implementation 'com.facebook.react:react-native:+' + implementation 'com.facebook.react:react-native:0.66.3' } From 8caab0acefa704d2edeaa24e9d3c2c0225894d73 Mon Sep 17 00:00:00 2001 From: Ricardo Corrie Date: Fri, 9 Dec 2022 14:42:31 -0600 Subject: [PATCH 09/17] Adds group calling api --- actions.js | 5 +++++ index.d.ts | 3 +++ index.js | 2 ++ ios/RNCallKeep/RNCallKeep.m | 26 ++++++++++++++++++++++++++ 4 files changed, 36 insertions(+) diff --git a/actions.js b/actions.js index 4e936360..82a61507 100644 --- a/actions.js +++ b/actions.js @@ -11,6 +11,7 @@ const RNCallKeepDidDeactivateAudioSession = 'RNCallKeepDidDeactivateAudioSession const RNCallKeepDidDisplayIncomingCall = 'RNCallKeepDidDisplayIncomingCall'; const RNCallKeepDidPerformSetMutedCallAction = 'RNCallKeepDidPerformSetMutedCallAction'; const RNCallKeepDidToggleHoldAction = 'RNCallKeepDidToggleHoldAction'; +const RNCallKeepPerformGroupCallAction = 'RNCallKeepPerformGroupCallAction'; const RNCallKeepDidPerformDTMFAction = 'RNCallKeepDidPerformDTMFAction'; const RNCallKeepProviderReset = 'RNCallKeepProviderReset'; const RNCallKeepCheckReachability = 'RNCallKeepCheckReachability'; @@ -63,6 +64,9 @@ const didPerformSetMutedCallAction = handler => const didToggleHoldCallAction = handler => eventEmitter.addListener(RNCallKeepDidToggleHoldAction, handler); +const performGroupCallAction = handler => + eventEmitter.addListener(RNCallKeepPerformGroupCallAction, handler); + const didPerformDTMFAction = handler => eventEmitter.addListener(RNCallKeepDidPerformDTMFAction, (data) => handler(data)); @@ -95,6 +99,7 @@ export const listeners = { didDisplayIncomingCall, didPerformSetMutedCallAction, didToggleHoldCallAction, + performGroupCallAction, didPerformDTMFAction, didResetProvider, checkReachability, diff --git a/index.d.ts b/index.d.ts index cd948ed8..bde37b28 100644 --- a/index.d.ts +++ b/index.d.ts @@ -7,6 +7,7 @@ declare module 'react-native-callkeep' { 'didDeactivateAudioSession' | 'didDisplayIncomingCall' | 'didToggleHoldCallAction' | + 'performGroupCallAction' | 'didPerformDTMFAction' | 'didResetProvider' | 'checkReachability' | @@ -175,6 +176,8 @@ declare module 'react-native-callkeep' { static toggleAudioRouteSpeaker(uuid: string, routeSpeaker: boolean): void static setOnHold(uuid: string, held: boolean): void + + static setGroupCall(activeUuid: string, heldUuid: string): void static setConnectionState(uuid: string, state: number): void diff --git a/index.js b/index.js index 3e1df0f0..59cb9eec 100644 --- a/index.js +++ b/index.js @@ -258,6 +258,8 @@ class RNCallKeep { }; setOnHold = (uuid, shouldHold) => RNCallKeepModule.setOnHold(uuid, shouldHold); + + setGroupCall = (activeUuid, heldUuid) => RNCallKeepModule.setGroupCall(activeUuid, heldUuid); setConnectionState = (uuid, state) => isIOS ? null : RNCallKeepModule.setConnectionState(uuid, state); diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index 416821c5..e2d764d3 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -33,6 +33,7 @@ static NSString *const RNCallKeepDidPerformSetMutedCallAction = @"RNCallKeepDidPerformSetMutedCallAction"; static NSString *const RNCallKeepPerformPlayDTMFCallAction = @"RNCallKeepDidPerformDTMFAction"; static NSString *const RNCallKeepDidToggleHoldAction = @"RNCallKeepDidToggleHoldAction"; +static NSString *const RNCallKeepPerformGroupCallAction = @"RNCallKeepPerformGroupCallAction"; static NSString *const RNCallKeepProviderReset = @"RNCallKeepProviderReset"; static NSString *const RNCallKeepCheckReachability = @"RNCallKeepCheckReachability"; static NSString *const RNCallKeepDidChangeAudioRoute = @"RNCallKeepDidChangeAudioRoute"; @@ -112,6 +113,7 @@ - (void)dealloc RNCallKeepDidPerformSetMutedCallAction, RNCallKeepPerformPlayDTMFCallAction, RNCallKeepDidToggleHoldAction, + RNCallKeepPerformGroupCallAction, RNCallKeepProviderReset, RNCallKeepCheckReachability, RNCallKeepDidLoadWithEvents, @@ -387,6 +389,20 @@ + (void)setup:(NSDictionary *)options { [self requestTransaction:transaction]; } +RCT_EXPORT_METHOD(setGroupCall:(NSString *)activeUuidString :(NSString *)heldUuidString) +{ +#ifdef DEBUG + NSLog(@"[RNCallKeep][setGroupCall] activeUuidString = %@, heldUuidString = %d", activeUuidString, heldUuidString); +#endif + NSUUID *activeUuid = [[NSUUID alloc] initWithUUIDString:activeUuidString]; + NSUUID *heldUuid = [[NSUUID alloc] initWithUUIDString:heldUuidString]; + CXSetGroupCallAction *setGroupCallAction = [[CXSetGroupCallAction alloc] initWithCallUUID:heldUuid callUUIDToGroupWith:activeUuid]; + CXTransaction *transaction = [[CXTransaction alloc] init]; + [transaction addAction:setGroupCallAction]; + + [self requestTransaction:transaction]; +} + RCT_EXPORT_METHOD(_startCallActionEventListenerAdded) { _isStartCallActionEventListenerAdded = YES; @@ -1052,6 +1068,16 @@ -(void)provider:(CXProvider *)provider performSetHeldCallAction:(CXSetHeldCallAc [action fulfill]; } +-(void)provider:(CXProvider *)provider performSetGroupCallAction:(CXSetGroupCallAction *)action +{ +#ifdef DEBUG + NSLog(@"[RNCallKeep][CXProviderDelegate][provider:performSetGroupCallAction]"); +#endif + + [self sendEventWithNameWrapper:RNCallKeepPerformGroupCallAction body:@{ @"activeCallUUID": [action.callUUID.UUIDString lowercaseString], @"heldCallUUID": [action.callUUIDToGroupWith.UUIDString lowercaseString] }]; + [action fulfill]; +} + - (void)provider:(CXProvider *)provider performPlayDTMFCallAction:(CXPlayDTMFCallAction *)action { #ifdef DEBUG NSLog(@"[RNCallKeep][CXProviderDelegate][provider:performPlayDTMFCallAction]"); From d837589ea65d00ba010bfd253b0a1cf42b4d6f66 Mon Sep 17 00:00:00 2001 From: Ricardo Corrie Date: Mon, 23 Jan 2023 12:13:34 -0600 Subject: [PATCH 10/17] bug/MOB-5197: 3 way calling: Call is ended after tap merge button (Android native call and iOS mob app) --- index.d.ts | 1 + index.js | 1 + ios/RNCallKeep/RNCallKeep.h | 1 + ios/RNCallKeep/RNCallKeep.m | 13 ++++++++++++- 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index bde37b28..5dedf4b9 100644 --- a/index.d.ts +++ b/index.d.ts @@ -178,6 +178,7 @@ declare module 'react-native-callkeep' { static setOnHold(uuid: string, held: boolean): void static setGroupCall(activeUuid: string, heldUuid: string): void + static setGroupCallFulfilled(): void static setConnectionState(uuid: string, state: number): void diff --git a/index.js b/index.js index 59cb9eec..40be5af4 100644 --- a/index.js +++ b/index.js @@ -260,6 +260,7 @@ class RNCallKeep { setOnHold = (uuid, shouldHold) => RNCallKeepModule.setOnHold(uuid, shouldHold); setGroupCall = (activeUuid, heldUuid) => RNCallKeepModule.setGroupCall(activeUuid, heldUuid); + setGroupCallFulfilled = () => RNCallKeepModule.setGroupCallFulfilled(); setConnectionState = (uuid, state) => isIOS ? null : RNCallKeepModule.setConnectionState(uuid, state); diff --git a/ios/RNCallKeep/RNCallKeep.h b/ios/RNCallKeep/RNCallKeep.h index c8e7bbdf..850dfc95 100644 --- a/ios/RNCallKeep/RNCallKeep.h +++ b/ios/RNCallKeep/RNCallKeep.h @@ -18,6 +18,7 @@ @property (nonatomic, strong) CXCallController *callKeepCallController; @property (nonatomic, strong) CXProvider *callKeepProvider; +@property (nonatomic, strong) CXSetGroupCallAction * callKeepGroupCallAction; + (BOOL)application:(UIApplication *)application openURL:(NSURL *)url diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index e2d764d3..e7b40365 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -403,6 +403,16 @@ + (void)setup:(NSDictionary *)options { [self requestTransaction:transaction]; } +RCT_EXPORT_METHOD(setGroupCallFulfilled) +{ +#ifdef DEBUG + NSLog(@"[RNCallKeep][setGroupCallFulfilled]"); +#endif + if (self.callKeepGroupCallAction != nil) { + [self.callKeepGroupCallAction fulfill]; + } +} + RCT_EXPORT_METHOD(_startCallActionEventListenerAdded) { _isStartCallActionEventListenerAdded = YES; @@ -1075,7 +1085,8 @@ -(void)provider:(CXProvider *)provider performSetGroupCallAction:(CXSetGroupCall #endif [self sendEventWithNameWrapper:RNCallKeepPerformGroupCallAction body:@{ @"activeCallUUID": [action.callUUID.UUIDString lowercaseString], @"heldCallUUID": [action.callUUIDToGroupWith.UUIDString lowercaseString] }]; - [action fulfill]; + + self.callKeepGroupCallAction = action; } - (void)provider:(CXProvider *)provider performPlayDTMFCallAction:(CXPlayDTMFCallAction *)action { From b80f36e232d2df52edd601e8cc43f0933c3a563a Mon Sep 17 00:00:00 2001 From: Ricardo Corrie Date: Tue, 12 Sep 2023 14:19:51 -0500 Subject: [PATCH 11/17] bug/MOB-5897: Phone sound gets activated instead of Speaker one after user receives incoming n2p call when on ongoing conference call --- index.d.ts | 4 ++++ ios/RNCallKeep/RNCallKeep.h | 3 +++ ios/RNCallKeep/RNCallKeep.m | 32 ++++++++++++++++++++++---------- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/index.d.ts b/index.d.ts index 5dedf4b9..6fd1d207 100644 --- a/index.d.ts +++ b/index.d.ts @@ -203,5 +203,9 @@ declare module 'react-native-callkeep' { static setCurrentCallActive(callUUID: string): void static backToForeground(): void + + static configureVoiceAudioSession(): void + + static configureVideoAudioSession(): void } } diff --git a/ios/RNCallKeep/RNCallKeep.h b/ios/RNCallKeep/RNCallKeep.h index 850dfc95..fc1ae07d 100644 --- a/ios/RNCallKeep/RNCallKeep.h +++ b/ios/RNCallKeep/RNCallKeep.h @@ -48,4 +48,7 @@ continueUserActivity:(NSUserActivity *)userActivity + (void)setup:(NSDictionary *)options; ++ (void)configureVoiceAudioSession; ++ (void)configureVideoAudioSession; + @end diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index e7b40365..a5adfde4 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -787,7 +787,7 @@ + (void)reportNewIncomingCall:(NSString *)uuidString if (error == nil) { // Workaround per https://forums.developer.apple.com/message/169511 if ([callKeep lessThanIos10_2]) { - [callKeep configureAudioSession]; + [callKeep configureAudioSession:AVAudioSessionModeVoiceChat]; } } if (completion != nil) { @@ -875,35 +875,35 @@ + (CXProviderConfiguration *)getProviderConfiguration:(NSDictionary*)settings return providerConfiguration; } -- (void)configureAudioSession +- (void)configureAudioSession:(AVAudioSessionMode)mode { #ifdef DEBUG NSLog(@"[RNCallKeep][configureAudioSession] Activating audio session"); #endif @try{ NSError* err = nil; - + AVAudioSession* audioSession = [AVAudioSession sharedInstance]; - BOOL isConfigured = [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord mode:AVAudioSessionModeVoiceChat options: AVAudioSessionCategoryOptionAllowAirPlay | AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionAllowBluetoothA2DP error:&err]; + BOOL isConfigured = [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord mode:mode options: AVAudioSessionCategoryOptionAllowAirPlay | AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionAllowBluetoothA2DP error:&err]; if(!isConfigured){ NSLog(@"[RNCallKeep][configureAudioSession][setCategory] failed"); [NSException raise:@"audioSession#setCategory failed" format:@"error: %@", err]; } - + double sampleRate = 44100.0; BOOL sampleRateSetted = [audioSession setPreferredSampleRate:sampleRate error:&err]; if(!sampleRateSetted){ NSLog(@"[RNCallKeep][configureAudioSession][setPreferredSampleRate] failed"); [NSException raise:@"audioSession#setPreferredSampleRate failed" format:@"error: %@", err]; } - + NSTimeInterval bufferDuration = .005; BOOL bufferSetted = [audioSession setPreferredIOBufferDuration:bufferDuration error:&err]; if(!bufferSetted){ NSLog(@"[RNCallKeep][configureAudioSession][setPreferredIOBufferDuration] failed"); [NSException raise:@"audioSession#setPreferredIOBufferDuration failed" format:@"error: %@", err]; } - + BOOL isActivated = [audioSession setActive:TRUE error:&err]; if(!isActivated){ NSLog(@"[RNCallKeep][configureAudioSession][setActive] failed"); @@ -916,6 +916,7 @@ - (void)configureAudioSession } + + (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options NS_AVAILABLE_IOS(9_0) @@ -1027,7 +1028,7 @@ - (void)provider:(CXProvider *)provider performStartCallAction:(CXStartCallActio NSLog(@"[RNCallKeep][CXProviderDelegate][provider:performStartCallAction]"); #endif //do this first, audio sessions are flakey - [self configureAudioSession]; + //[self configureAudioSession]; //tell the JS to actually make the call [self sendEventWithNameWrapper:RNCallKeepDidReceiveStartCallAction body:@{ @"callUUID": [action.callUUID.UUIDString lowercaseString], @"handle": action.handle.value }]; [action fulfill]; @@ -1047,13 +1048,24 @@ - (void)provider:(CXProvider *)provider performStartCallAction:(CXStartCallActio [self.callKeepProvider reportCallWithUUID:uuid updated:callUpdate]; } +RCT_EXPORT_METHOD(configureVoiceAudioSession) +{ + [self configureAudioSession:AVAudioSessionModeVoiceChat]; +} + + +RCT_EXPORT_METHOD(configureVideoAudioSession) +{ + [self configureAudioSession:AVAudioSessionModeVideoChat]; +} + // Answering incoming call - (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action { #ifdef DEBUG NSLog(@"[RNCallKeep][CXProviderDelegate][provider:performAnswerCallAction]"); #endif - [self configureAudioSession]; + //[self configureAudioSession]; [self sendEventWithNameWrapper:RNCallKeepPerformAnswerCallAction body:@{ @"callUUID": [action.callUUID.UUIDString lowercaseString] }]; [action fulfill]; } @@ -1126,7 +1138,7 @@ - (void)provider:(CXProvider *)provider didActivateAudioSession:(AVAudioSession }; [[NSNotificationCenter defaultCenter] postNotificationName:AVAudioSessionInterruptionNotification object:nil userInfo:userInfo]; - [self configureAudioSession]; + //[self configureAudioSession]; [self sendEventWithNameWrapper:RNCallKeepDidActivateAudioSession body:nil]; } From 06dddf6f80e9053f215b08f317345e98e593a970 Mon Sep 17 00:00:00 2001 From: Ricardo Corrie Date: Wed, 13 Sep 2023 09:30:29 -0500 Subject: [PATCH 12/17] Adds missing js methods --- index.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/index.js b/index.js index 40be5af4..eff241e2 100644 --- a/index.js +++ b/index.js @@ -350,6 +350,14 @@ class RNCallKeep { clearInitialEvents() { return RNCallKeepModule.clearInitialEvents(); } + + configureVideoAudioSession() { + return RNCallKeepModule.configureVideoAudioSession(); + } + + configureVoiceAudioSession() { + return RNCallKeepModule.configureVoiceAudioSession(); + } } export default new RNCallKeep(); From 843436434e885dfacb1a8c05a356e930071160c9 Mon Sep 17 00:00:00 2001 From: Ricardo Corrie Date: Thu, 18 Jan 2024 15:05:31 -0600 Subject: [PATCH 13/17] bug/MOB-5329: iOS: No outbound call ringing sound when placing a call from native call history on iPhone (CS3) --- index.d.ts | 2 ++ index.js | 13 +++++++++++++ ios/RNCallKeep/RNCallKeep.h | 1 + ios/RNCallKeep/RNCallKeep.m | 22 +++++++++++++++++++++- 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 6fd1d207..f06767db 100644 --- a/index.d.ts +++ b/index.d.ts @@ -145,6 +145,8 @@ declare module 'react-native-callkeep' { */ static isCallActive(uuid: string): Promise + static isAudioSessionActive(): Promise + static getCalls(): Promise static getAudioRoutes(): Promise diff --git a/index.js b/index.js index eff241e2..23d159d4 100644 --- a/index.js +++ b/index.js @@ -27,6 +27,17 @@ class RNCallKeep { addEventListener = (type, handler) => { const listener = listeners[type](handler); + /** + * xxx https://idtjira.atlassian.net/browse/MOB-5329 + */ + if (type === 'didActivateAudioSession') { + this.isAudioSessionActive().then(isActive => { + if (isActive) { + handler() + } + }) + } + this._callkeepEventHandlers.set(type, listener); }; @@ -170,6 +181,8 @@ class RNCallKeep { isCallActive = async (uuid) => await RNCallKeepModule.isCallActive(uuid); + isAudioSessionActive = RNCallKeepModule.isAudioSessionActive; + getCalls = () => { if (isIOS) { return RNCallKeepModule.getCalls(); diff --git a/ios/RNCallKeep/RNCallKeep.h b/ios/RNCallKeep/RNCallKeep.h index fc1ae07d..8df6c0fb 100644 --- a/ios/RNCallKeep/RNCallKeep.h +++ b/ios/RNCallKeep/RNCallKeep.h @@ -45,6 +45,7 @@ continueUserActivity:(NSUserActivity *)userActivity reason:(int)reason; + (BOOL)isCallActive:(NSString *)uuidString; ++ (BOOL)isAudioSessionActive; + (void)setup:(NSDictionary *)options; diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index a5adfde4..272b543d 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -44,6 +44,7 @@ @implementation RNCallKeep NSOperatingSystemVersion _version; BOOL _isStartCallActionEventListenerAdded; bool _hasListeners; + bool _isAudioSessionActive; bool _isReachable; NSMutableArray *_delayedEvents; } @@ -163,6 +164,13 @@ - (void)sendEventWithNameWrapper:(NSString *)name body:(id)body { nil ]; [_delayedEvents addObject:dictionary]; + + } + + if ([name isEqualToString:@"RNCallKeepDidReceiveStartCallAction"]) { + [_delayedEvents addObject: [NSDictionary dictionaryWithObjectsAndKeys: + @"RNCallKeepDidActivateAudioSession", @"name", nil]]; + _isAudioSessionActive = YES; } } @@ -360,7 +368,7 @@ + (void)setup:(NSDictionary *)options { NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:uuidString]; CXEndCallAction *endCallAction = [[CXEndCallAction alloc] initWithCallUUID:uuid]; CXTransaction *transaction = [[CXTransaction alloc] initWithAction:endCallAction]; - + _isAudioSessionActive = NO; [self requestTransaction:transaction]; } @@ -372,6 +380,7 @@ + (void)setup:(NSDictionary *)options { for (CXCall *call in self.callKeepCallController.callObserver.calls) { CXEndCallAction *endCallAction = [[CXEndCallAction alloc] initWithCallUUID:call.UUID]; CXTransaction *transaction = [[CXTransaction alloc] initWithAction:endCallAction]; + _isAudioSessionActive = NO; [self requestTransaction:transaction]; } } @@ -491,6 +500,12 @@ + (void)setup:(NSDictionary *)options { [self requestTransaction:transaction]; } +RCT_EXPORT_METHOD(isAudioSessionActive:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) +{ + resolve([NSNumber numberWithBool:_isAudioSessionActive]); +} + RCT_EXPORT_METHOD(isCallActive:(NSString *)uuidString isCallActiveResolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) @@ -999,6 +1014,7 @@ + (BOOL)application:(UIApplication *)application }; RNCallKeep *callKeep = [RNCallKeep allocWithZone: nil]; + [callKeep sendEventWithNameWrapper:RNCallKeepDidReceiveStartCallAction body:userInfo]; return YES; } @@ -1076,6 +1092,7 @@ - (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *) #ifdef DEBUG NSLog(@"[RNCallKeep][CXProviderDelegate][provider:performEndCallAction]"); #endif + _isAudioSessionActive = NO; [self sendEventWithNameWrapper:RNCallKeepPerformEndCallAction body:@{ @"callUUID": [action.callUUID.UUIDString lowercaseString] }]; [action fulfill]; } @@ -1139,6 +1156,8 @@ - (void)provider:(CXProvider *)provider didActivateAudioSession:(AVAudioSession [[NSNotificationCenter defaultCenter] postNotificationName:AVAudioSessionInterruptionNotification object:nil userInfo:userInfo]; //[self configureAudioSession]; + _isAudioSessionActive = YES; + [self sendEventWithNameWrapper:RNCallKeepDidActivateAudioSession body:nil]; } @@ -1147,6 +1166,7 @@ - (void)provider:(CXProvider *)provider didDeactivateAudioSession:(AVAudioSessio #ifdef DEBUG NSLog(@"[RNCallKeep][CXProviderDelegate][provider:didDeactivateAudioSession]"); #endif + _isAudioSessionActive = NO; [self sendEventWithNameWrapper:RNCallKeepDidDeactivateAudioSession body:nil]; } From 6228ac972f5441101917a73acbee113f21e5d817 Mon Sep 17 00:00:00 2001 From: Ricardo Corrie <37703740+rcidt@users.noreply.github.com> Date: Thu, 11 Jul 2024 20:05:30 -0400 Subject: [PATCH 14/17] Update AndroidManifest.xml --- android/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index fe2b6cce..916b9907 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,5 +1,5 @@ - + Date: Thu, 11 Jul 2024 20:05:50 -0400 Subject: [PATCH 15/17] Update build.gradle --- android/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/android/build.gradle b/android/build.gradle index 2e7b48a7..cc1db228 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -16,6 +16,7 @@ def safeExtGet(prop, fallback) { } android { + namespace 'io.wazo.callkeep' compileSdkVersion safeExtGet('compileSdkVersion', 28) defaultConfig { From 3d1bccfd5ae8e67bcb529bdb2729fa831582d59c Mon Sep 17 00:00:00 2001 From: Ricardo Corrie <37703740+rcidt@users.noreply.github.com> Date: Fri, 12 Jul 2024 13:16:56 -0400 Subject: [PATCH 16/17] Update build.gradle --- android/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/android/build.gradle b/android/build.gradle index cc1db228..01c9b486 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -33,4 +33,5 @@ repositories { dependencies { implementation 'com.facebook.react:react-native:0.66.3' + implementation "androidx.localbroadcastmanager:localbroadcastmanager:1.1.0" } From df3c620345d5057d55c7e92ff10b5062cf0aeb74 Mon Sep 17 00:00:00 2001 From: Janusz Kolarczyk Date: Fri, 4 Oct 2024 15:33:29 +0200 Subject: [PATCH 17/17] Fix no audio if app killed before call --- ios/RNCallKeep/RNCallKeep.m | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index 4fa92503..694ff9c4 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -826,9 +826,7 @@ + (void)reportNewIncomingCall:(NSString *)uuidString }]; if (error == nil) { // Workaround per https://forums.developer.apple.com/message/169511 - if ([callKeep lessThanIos10_2]) { - [callKeep configureAudioSession:AVAudioSessionModeVoiceChat]; - } + [callKeep configureAudioSession:AVAudioSessionModeVoiceChat]; } if (completion != nil) { completion();