[iOS] Proxy CallKit API to be a feature of the SDK
With this the RN component and the consumer app can share same CallKit provider, configuration, and enable to be part of multiple listeners of the CallKit flow events. The main driver of this is to enable the consumer app to be able to report an incoming call to the OS before loading the JitsiMeetView. Once the user answers the call, the app can instantiate a JitsiMeetView, pass the CallKit call UUIID, and the Jitsi Meet components will handle the connection and report back to CallKit that the call has been established.
This commit is contained in:
parent
520bb8bd22
commit
e5309a6482
|
@ -38,6 +38,9 @@
|
||||||
B386B85D20981A75000DEF7A /* Invite.m in Sources */ = {isa = PBXBuildFile; fileRef = B386B85620981A75000DEF7A /* Invite.m */; };
|
B386B85D20981A75000DEF7A /* Invite.m in Sources */ = {isa = PBXBuildFile; fileRef = B386B85620981A75000DEF7A /* Invite.m */; };
|
||||||
C6245F5D2053091D0040BE68 /* image-resize@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5B2053091D0040BE68 /* image-resize@2x.png */; };
|
C6245F5D2053091D0040BE68 /* image-resize@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5B2053091D0040BE68 /* image-resize@2x.png */; };
|
||||||
C6245F5E2053091D0040BE68 /* image-resize@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5C2053091D0040BE68 /* image-resize@3x.png */; };
|
C6245F5E2053091D0040BE68 /* image-resize@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C6245F5C2053091D0040BE68 /* image-resize@3x.png */; };
|
||||||
|
C69EFA0C209A0F660027712B /* JMCallKitNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA09209A0F650027712B /* JMCallKitNotifier.swift */; };
|
||||||
|
C69EFA0D209A0F660027712B /* JMCallKitProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0A209A0F660027712B /* JMCallKitProxy.swift */; };
|
||||||
|
C69EFA0E209A0F660027712B /* JMCallKitEventListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0B209A0F660027712B /* JMCallKitEventListener.swift */; };
|
||||||
C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425E204EF76800E062DD /* DragGestureController.swift */; };
|
C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425E204EF76800E062DD /* DragGestureController.swift */; };
|
||||||
C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */; };
|
C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */; };
|
||||||
C6F99C15204DB63E0001F710 /* JitsiMeetView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */; };
|
C6F99C15204DB63E0001F710 /* JitsiMeetView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */; };
|
||||||
|
@ -83,6 +86,9 @@
|
||||||
B386B85620981A75000DEF7A /* Invite.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Invite.m; sourceTree = "<group>"; };
|
B386B85620981A75000DEF7A /* Invite.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Invite.m; sourceTree = "<group>"; };
|
||||||
C6245F5B2053091D0040BE68 /* image-resize@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "image-resize@2x.png"; path = "src/picture-in-picture/image-resize@2x.png"; sourceTree = "<group>"; };
|
C6245F5B2053091D0040BE68 /* image-resize@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "image-resize@2x.png"; path = "src/picture-in-picture/image-resize@2x.png"; sourceTree = "<group>"; };
|
||||||
C6245F5C2053091D0040BE68 /* image-resize@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "image-resize@3x.png"; path = "src/picture-in-picture/image-resize@3x.png"; sourceTree = "<group>"; };
|
C6245F5C2053091D0040BE68 /* image-resize@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "image-resize@3x.png"; path = "src/picture-in-picture/image-resize@3x.png"; sourceTree = "<group>"; };
|
||||||
|
C69EFA09209A0F650027712B /* JMCallKitNotifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JMCallKitNotifier.swift; sourceTree = "<group>"; };
|
||||||
|
C69EFA0A209A0F660027712B /* JMCallKitProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JMCallKitProxy.swift; sourceTree = "<group>"; };
|
||||||
|
C69EFA0B209A0F660027712B /* JMCallKitEventListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JMCallKitEventListener.swift; sourceTree = "<group>"; };
|
||||||
C6A3425E204EF76800E062DD /* DragGestureController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragGestureController.swift; sourceTree = "<group>"; };
|
C6A3425E204EF76800E062DD /* DragGestureController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragGestureController.swift; sourceTree = "<group>"; };
|
||||||
C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPViewCoordinator.swift; sourceTree = "<group>"; };
|
C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPViewCoordinator.swift; sourceTree = "<group>"; };
|
||||||
C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetView+Private.h"; sourceTree = "<group>"; };
|
C6F99C13204DB63D0001F710 /* JitsiMeetView+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetView+Private.h"; sourceTree = "<group>"; };
|
||||||
|
@ -138,6 +144,7 @@
|
||||||
0BD906E71EC0C00300C8C18E /* src */ = {
|
0BD906E71EC0C00300C8C18E /* src */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
C69EFA02209A0EFD0027712B /* callkit */,
|
||||||
B386B84F20981A11000DEF7A /* invite */,
|
B386B84F20981A11000DEF7A /* invite */,
|
||||||
C6A3426B204F127900E062DD /* picture-in-picture */,
|
C6A3426B204F127900E062DD /* picture-in-picture */,
|
||||||
0BCA495C1EC4B6C600B793EE /* AudioMode.m */,
|
0BCA495C1EC4B6C600B793EE /* AudioMode.m */,
|
||||||
|
@ -198,6 +205,16 @@
|
||||||
name = Pods;
|
name = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
C69EFA02209A0EFD0027712B /* callkit */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
C69EFA0B209A0F660027712B /* JMCallKitEventListener.swift */,
|
||||||
|
C69EFA09209A0F650027712B /* JMCallKitNotifier.swift */,
|
||||||
|
C69EFA0A209A0F660027712B /* JMCallKitProxy.swift */,
|
||||||
|
);
|
||||||
|
path = callkit;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
C6A3426B204F127900E062DD /* picture-in-picture */ = {
|
C6A3426B204F127900E062DD /* picture-in-picture */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -390,7 +407,10 @@
|
||||||
0BCA495F1EC4B6C600B793EE /* AudioMode.m in Sources */,
|
0BCA495F1EC4B6C600B793EE /* AudioMode.m in Sources */,
|
||||||
0B44A0191F902126009D1D64 /* MPVolumeViewManager.m in Sources */,
|
0B44A0191F902126009D1D64 /* MPVolumeViewManager.m in Sources */,
|
||||||
0BCA49611EC4B6C600B793EE /* Proximity.m in Sources */,
|
0BCA49611EC4B6C600B793EE /* Proximity.m in Sources */,
|
||||||
|
C69EFA0C209A0F660027712B /* JMCallKitNotifier.swift in Sources */,
|
||||||
C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */,
|
C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */,
|
||||||
|
C69EFA0D209A0F660027712B /* JMCallKitProxy.swift in Sources */,
|
||||||
|
C69EFA0E209A0F660027712B /* JMCallKitEventListener.swift in Sources */,
|
||||||
0B412F191EDEC65D00B1A0A6 /* JitsiMeetView.m in Sources */,
|
0B412F191EDEC65D00B1A0A6 /* JitsiMeetView.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#import <React/RCTEventEmitter.h>
|
#import <React/RCTEventEmitter.h>
|
||||||
#import <React/RCTUtils.h>
|
#import <React/RCTUtils.h>
|
||||||
|
|
||||||
|
#import <JitsiMeet/JitsiMeet-Swift.h>
|
||||||
|
|
||||||
// The events emitted/supported by RNCallKit:
|
// The events emitted/supported by RNCallKit:
|
||||||
static NSString * const RNCallKitPerformAnswerCallAction
|
static NSString * const RNCallKitPerformAnswerCallAction
|
||||||
= @"performAnswerCallAction";
|
= @"performAnswerCallAction";
|
||||||
|
@ -37,14 +39,10 @@ static NSString * const RNCallKitPerformSetMutedCallAction
|
||||||
static NSString * const RNCallKitProviderDidReset
|
static NSString * const RNCallKitProviderDidReset
|
||||||
= @"providerDidReset";
|
= @"providerDidReset";
|
||||||
|
|
||||||
@interface RNCallKit : RCTEventEmitter <CXProviderDelegate>
|
@interface RNCallKit : RCTEventEmitter <JMCallKitEventListener>
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation RNCallKit
|
@implementation RNCallKit
|
||||||
{
|
|
||||||
CXCallController *_callController;
|
|
||||||
CXProvider *_provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_EXTERN void RCTRegisterModule(Class);
|
RCT_EXTERN void RCTRegisterModule(Class);
|
||||||
|
|
||||||
|
@ -70,35 +68,8 @@ RCT_EXTERN void RCTRegisterModule(Class);
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display the incoming call to the user
|
- (void)dealloc {
|
||||||
RCT_EXPORT_METHOD(displayIncomingCall:(NSString *)callUUID
|
[JMCallKitProxy removeListener:self];
|
||||||
handle:(NSString *)handle
|
|
||||||
hasVideo:(BOOL)hasVideo
|
|
||||||
resolve:(RCTPromiseResolveBlock)resolve
|
|
||||||
reject:(RCTPromiseRejectBlock)reject) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
NSLog(@"[RNCallKit][displayIncomingCall] callUUID = %@", callUUID);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
|
|
||||||
CXCallUpdate *callUpdate = [[CXCallUpdate alloc] init];
|
|
||||||
callUpdate.remoteHandle
|
|
||||||
= [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:handle];
|
|
||||||
callUpdate.supportsDTMF = NO;
|
|
||||||
callUpdate.supportsHolding = NO;
|
|
||||||
callUpdate.supportsGrouping = NO;
|
|
||||||
callUpdate.supportsUngrouping = NO;
|
|
||||||
callUpdate.hasVideo = hasVideo;
|
|
||||||
|
|
||||||
[self.provider reportNewIncomingCallWithUUID:callUUID_
|
|
||||||
update:callUpdate
|
|
||||||
completion:^(NSError * _Nullable error) {
|
|
||||||
if (error) {
|
|
||||||
reject(nil, @"Error reporting new incoming call", error);
|
|
||||||
} else {
|
|
||||||
resolve(nil);
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// End call
|
// End call
|
||||||
|
@ -141,14 +112,12 @@ RCT_EXPORT_METHOD(setProviderConfiguration:(NSDictionary *)dictionary) {
|
||||||
dictionary);
|
dictionary);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CXProviderConfiguration *configuration
|
if (![JMCallKitProxy hasProviderBeenConfigurated]) {
|
||||||
= [self providerConfigurationFromDictionary:dictionary];
|
[self configureProviderFromDictionary:dictionary];
|
||||||
if (_provider) {
|
|
||||||
_provider.configuration = configuration;
|
|
||||||
} else {
|
|
||||||
_provider = [[CXProvider alloc] initWithConfiguration:configuration];
|
|
||||||
[_provider setDelegate:self queue:nil];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// register to receive CallKit proxy events
|
||||||
|
[JMCallKitProxy addListener: self];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start outgoing call
|
// Start outgoing call
|
||||||
|
@ -162,6 +131,15 @@ RCT_EXPORT_METHOD(startCall:(NSString *)callUUID
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
|
NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
|
||||||
|
|
||||||
|
// Don't start a call action if there's
|
||||||
|
// an active call for this UUID
|
||||||
|
// (i.e. JitsiMeetView was configured from an incoming call
|
||||||
|
if ([JMCallKitProxy hasActiveCallForUUID:callUUID]) {
|
||||||
|
resolve(nil);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CXHandle *handle_
|
CXHandle *handle_
|
||||||
= [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:handle];
|
= [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:handle];
|
||||||
CXStartCallAction *action
|
CXStartCallAction *action
|
||||||
|
@ -177,9 +155,9 @@ RCT_EXPORT_METHOD(reportCallFailed:(NSString *)callUUID
|
||||||
resolve:(RCTPromiseResolveBlock)resolve
|
resolve:(RCTPromiseResolveBlock)resolve
|
||||||
reject:(RCTPromiseRejectBlock)reject) {
|
reject:(RCTPromiseRejectBlock)reject) {
|
||||||
NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
|
NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
|
||||||
[self.provider reportCallWithUUID:callUUID_
|
[JMCallKitProxy reportCallWith:callUUID_
|
||||||
endedAtDate:[NSDate date]
|
endedAt:nil
|
||||||
reason:CXCallEndedReasonFailed];
|
reason:CXCallEndedReasonFailed];
|
||||||
resolve(nil);
|
resolve(nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,8 +166,8 @@ RCT_EXPORT_METHOD(reportConnectedOutgoingCall:(NSString *)callUUID
|
||||||
resolve:(RCTPromiseResolveBlock)resolve
|
resolve:(RCTPromiseResolveBlock)resolve
|
||||||
reject:(RCTPromiseRejectBlock)reject) {
|
reject:(RCTPromiseRejectBlock)reject) {
|
||||||
NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
|
NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
|
||||||
[self.provider reportOutgoingCallWithUUID:callUUID_
|
[JMCallKitProxy reportOutgoingCallWith:callUUID_
|
||||||
connectedAtDate:[NSDate date]];
|
connectedAt:nil];
|
||||||
resolve(nil);
|
resolve(nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,36 +184,20 @@ RCT_EXPORT_METHOD(updateCall:(NSString *)callUUID
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
|
NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
|
||||||
CXCallUpdate *callUpdate = [[CXCallUpdate alloc] init];
|
NSString *displayName = options[@"displayName"];
|
||||||
if (options[@"displayName"]) {
|
BOOL hasVideo = [(NSNumber*)options[@"hasVideo"] boolValue];
|
||||||
callUpdate.localizedCallerName = options[@"displayName"];
|
|
||||||
}
|
[JMCallKitProxy reportCallUpdateWith:callUUID_
|
||||||
if (options[@"hasVideo"]) {
|
handle:nil
|
||||||
callUpdate.hasVideo = [(NSNumber*)options[@"hasVideo"] boolValue];
|
displayName:displayName
|
||||||
}
|
hasVideo:hasVideo];
|
||||||
[self.provider reportCallWithUUID:callUUID_ updated:callUpdate];
|
|
||||||
resolve(nil);
|
resolve(nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Helper methods
|
#pragma mark - Helper methods
|
||||||
|
|
||||||
- (CXCallController *)callController {
|
- (void)configureProviderFromDictionary:(NSDictionary* )dictionary {
|
||||||
if (!_callController) {
|
|
||||||
_callController = [[CXCallController alloc] init];
|
|
||||||
}
|
|
||||||
|
|
||||||
return _callController;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CXProvider *)provider {
|
|
||||||
if (!_provider) {
|
|
||||||
[self setProviderConfiguration:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
return _provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CXProviderConfiguration *)providerConfigurationFromDictionary:(NSDictionary* )dictionary {
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
NSLog(@"[RNCallKit][providerConfigurationFromDictionary:]");
|
NSLog(@"[RNCallKit][providerConfigurationFromDictionary:]");
|
||||||
#endif
|
#endif
|
||||||
|
@ -251,30 +213,25 @@ RCT_EXPORT_METHOD(updateCall:(NSString *)callUUID
|
||||||
= [[NSBundle mainBundle] infoDictionary][@"CFBundleDisplayName"];
|
= [[NSBundle mainBundle] infoDictionary][@"CFBundleDisplayName"];
|
||||||
}
|
}
|
||||||
|
|
||||||
CXProviderConfiguration *providerConfiguration
|
|
||||||
= [[CXProviderConfiguration alloc] initWithLocalizedName:localizedName];
|
|
||||||
|
|
||||||
// iconTemplateImageData
|
// iconTemplateImageData
|
||||||
NSString *iconTemplateImageName = dictionary[@"iconTemplateImageName"];
|
NSString *iconTemplateImageName = dictionary[@"iconTemplateImageName"];
|
||||||
|
NSData *iconTemplateImageData;
|
||||||
if (iconTemplateImageName) {
|
if (iconTemplateImageName) {
|
||||||
UIImage *iconTemplateImage
|
UIImage *iconTemplateImage
|
||||||
= [UIImage imageNamed:iconTemplateImageName
|
= [UIImage imageNamed:iconTemplateImageName
|
||||||
inBundle:[NSBundle bundleForClass:self.class]
|
inBundle:[NSBundle bundleForClass:self.class]
|
||||||
compatibleWithTraitCollection:nil];
|
compatibleWithTraitCollection:nil];
|
||||||
if (iconTemplateImage) {
|
if (iconTemplateImage) {
|
||||||
providerConfiguration.iconTemplateImageData
|
iconTemplateImageData
|
||||||
= UIImagePNGRepresentation(iconTemplateImage);
|
= UIImagePNGRepresentation(iconTemplateImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
providerConfiguration.maximumCallGroups = 1;
|
NSString *ringtoneSound = dictionary[@"ringtoneSound"];
|
||||||
providerConfiguration.maximumCallsPerCallGroup = 1;
|
|
||||||
providerConfiguration.ringtoneSound = dictionary[@"ringtoneSound"];
|
[JMCallKitProxy configureCallKitProviderWithLocalizedName:localizedName
|
||||||
providerConfiguration.supportedHandleTypes
|
ringtoneSound:ringtoneSound
|
||||||
= [NSSet setWithObjects:@(CXHandleTypeGeneric), nil];
|
iconTemplateImageData:iconTemplateImageData];
|
||||||
providerConfiguration.supportsVideo = YES;
|
|
||||||
|
|
||||||
return providerConfiguration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)requestTransaction:(CXTransaction *)transaction
|
- (void)requestTransaction:(CXTransaction *)transaction
|
||||||
|
@ -284,8 +241,8 @@ RCT_EXPORT_METHOD(updateCall:(NSString *)callUUID
|
||||||
NSLog(@"[RNCallKit][requestTransaction] transaction = %@", transaction);
|
NSLog(@"[RNCallKit][requestTransaction] transaction = %@", transaction);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
[self.callController requestTransaction:transaction
|
[JMCallKitProxy request:transaction
|
||||||
completion:^(NSError * _Nullable error) {
|
completion:^(NSError * _Nullable error) {
|
||||||
if (error) {
|
if (error) {
|
||||||
NSLog(
|
NSLog(
|
||||||
@"[RNCallKit][requestTransaction] Error requesting transaction (%@): (%@)",
|
@"[RNCallKit][requestTransaction] Error requesting transaction (%@): (%@)",
|
||||||
|
@ -298,10 +255,10 @@ RCT_EXPORT_METHOD(updateCall:(NSString *)callUUID
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - CXProviderDelegate
|
#pragma mark - JitsiMeetCallKitListener
|
||||||
|
|
||||||
// Called when the provider has been reset. We should terminate all calls.
|
// Called when the provider has been reset. We should terminate all calls.
|
||||||
- (void)providerDidReset:(CXProvider *)provider {
|
- (void)providerDidReset {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
NSLog(@"[RNCallKit][CXProviderDelegate][providerDidReset:]");
|
NSLog(@"[RNCallKit][CXProviderDelegate][providerDidReset:]");
|
||||||
#endif
|
#endif
|
||||||
|
@ -310,84 +267,61 @@ RCT_EXPORT_METHOD(updateCall:(NSString *)callUUID
|
||||||
}
|
}
|
||||||
|
|
||||||
// Answering incoming call
|
// Answering incoming call
|
||||||
- (void) provider:(CXProvider *)provider
|
- (void) performAnswerCallWithUUID:(NSUUID *)UUID {
|
||||||
performAnswerCallAction:(CXAnswerCallAction *)action {
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
NSLog(@"[RNCallKit][CXProviderDelegate][provider:performAnswerCallAction:]");
|
NSLog(@"[RNCallKit][CXProviderDelegate][provider:performAnswerCallAction:]");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
[self sendEventWithName:RNCallKitPerformAnswerCallAction
|
[self sendEventWithName:RNCallKitPerformAnswerCallAction
|
||||||
body:@{ @"callUUID": action.callUUID.UUIDString }];
|
body:@{ @"callUUID": UUID.UUIDString }];
|
||||||
[action fulfill];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call ended, user request
|
// Call ended, user request
|
||||||
- (void) provider:(CXProvider *)provider
|
- (void) performEndCallWithUUID:(NSUUID *)UUID {
|
||||||
performEndCallAction:(CXEndCallAction *)action {
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
NSLog(@"[RNCallKit][CXProviderDelegate][provider:performEndCallAction:]");
|
NSLog(@"[RNCallKit][CXProviderDelegate][provider:performEndCallAction:]");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
[self sendEventWithName:RNCallKitPerformEndCallAction
|
[self sendEventWithName:RNCallKitPerformEndCallAction
|
||||||
body:@{ @"callUUID": action.callUUID.UUIDString }];
|
body:@{ @"callUUID": UUID.UUIDString }];
|
||||||
[action fulfill];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle audio mute from CallKit view
|
// Handle audio mute from CallKit view
|
||||||
- (void) provider:(CXProvider *)provider
|
- (void) performSetMutedCallWithUUID:(NSUUID *)UUID
|
||||||
performSetMutedCallAction:(CXSetMutedCallAction *)action {
|
isMuted:(BOOL)isMuted {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
NSLog(@"[RNCallKit][CXProviderDelegate][provider:performSetMutedCallAction:]");
|
NSLog(@"[RNCallKit][CXProviderDelegate][provider:performSetMutedCallAction:]");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
[self sendEventWithName:RNCallKitPerformSetMutedCallAction
|
[self sendEventWithName:RNCallKitPerformSetMutedCallAction
|
||||||
body:@{
|
body:@{
|
||||||
@"callUUID": action.callUUID.UUIDString,
|
@"callUUID": UUID.UUIDString,
|
||||||
@"muted": @(action.muted)
|
@"muted": @(isMuted)
|
||||||
}];
|
}];
|
||||||
[action fulfill];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starting outgoing call
|
// Starting outgoing call
|
||||||
- (void) provider:(CXProvider *)provider
|
- (void) performStartCallWithUUID:(NSUUID *)UUID
|
||||||
performStartCallAction:(CXStartCallAction *)action {
|
isVideo:(BOOL)isVideo {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
NSLog(@"[RNCallKit][CXProviderDelegate][provider:performStartCallAction:]");
|
NSLog(@"[RNCallKit][CXProviderDelegate][provider:performStartCallAction:]");
|
||||||
#endif
|
#endif
|
||||||
|
[JMCallKitProxy reportOutgoingCallWith:UUID
|
||||||
[action fulfill];
|
startedConnectingAt:nil];
|
||||||
|
|
||||||
// Update call info.
|
|
||||||
NSUUID *callUUID = action.callUUID;
|
|
||||||
CXCallUpdate *callUpdate = [[CXCallUpdate alloc] init];
|
|
||||||
callUpdate.remoteHandle = action.handle;
|
|
||||||
callUpdate.supportsDTMF = NO;
|
|
||||||
callUpdate.supportsHolding = NO;
|
|
||||||
callUpdate.supportsGrouping = NO;
|
|
||||||
callUpdate.supportsUngrouping = NO;
|
|
||||||
callUpdate.hasVideo = action.isVideo;
|
|
||||||
[provider reportCallWithUUID:callUUID updated:callUpdate];
|
|
||||||
|
|
||||||
// Notify the system about the outgoing call.
|
|
||||||
[provider reportOutgoingCallWithUUID:callUUID
|
|
||||||
startedConnectingAtDate:[NSDate date]];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following just help with debugging:
|
// The following just help with debugging:
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
||||||
- (void) provider:(CXProvider *)provider
|
- (void) providerDidActivateAudioSessionWithSession:(AVAudioSession *)session {
|
||||||
didActivateAudioSession:(AVAudioSession *)audioSession {
|
|
||||||
NSLog(@"[RNCallKit][CXProviderDelegate][provider:didActivateAudioSession:]");
|
NSLog(@"[RNCallKit][CXProviderDelegate][provider:didActivateAudioSession:]");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) provider:(CXProvider *)provider
|
- (void) providerDidDeactivateAudioSessionWithSession:(AVAudioSession *)session {
|
||||||
didDeactivateAudioSession:(AVAudioSession *)audioSession {
|
|
||||||
NSLog(@"[RNCallKit][CXProviderDelegate][provider:didDeactivateAudioSession:]");
|
NSLog(@"[RNCallKit][CXProviderDelegate][provider:didDeactivateAudioSession:]");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) provider:(CXProvider *)provider
|
- (void) providerTimedOutPerformingActionWithAction:(CXAction *)action {
|
||||||
timedOutPerformingAction:(CXAction *)action {
|
|
||||||
NSLog(@"[RNCallKit][CXProviderDelegate][provider:timedOutPerformingAction:]");
|
NSLog(@"[RNCallKit][CXProviderDelegate][provider:timedOutPerformingAction:]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright @ 2018-present Atlassian Pty Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import AVKit
|
||||||
|
import CallKit
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@objc public protocol JMCallKitEventListener: NSObjectProtocol {
|
||||||
|
|
||||||
|
@available(iOS 10.0, *)
|
||||||
|
@objc optional func providerDidReset()
|
||||||
|
|
||||||
|
@available(iOS 10.0, *)
|
||||||
|
@objc optional func performAnswerCall(UUID: UUID)
|
||||||
|
|
||||||
|
@available(iOS 10.0, *)
|
||||||
|
@objc optional func performEndCall(UUID: UUID)
|
||||||
|
|
||||||
|
@available(iOS 10.0, *)
|
||||||
|
@objc optional func performSetMutedCall(UUID: UUID, isMuted: Bool)
|
||||||
|
|
||||||
|
@available(iOS 10.0, *)
|
||||||
|
@objc optional func performStartCall(UUID: UUID, isVideo: Bool)
|
||||||
|
|
||||||
|
@available(iOS 10.0, *)
|
||||||
|
@objc optional func providerDidActivateAudioSession(session: AVAudioSession)
|
||||||
|
|
||||||
|
@available(iOS 10.0, *)
|
||||||
|
@objc optional func providerDidDeactivateAudioSession(session: AVAudioSession)
|
||||||
|
|
||||||
|
@available(iOS 10.0, *)
|
||||||
|
@objc optional func providerTimedOutPerformingAction(action: CXAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal struct JMCallKitEventListenerWrapper: Hashable {
|
||||||
|
|
||||||
|
public var hashValue: Int
|
||||||
|
|
||||||
|
internal weak var listener: JMCallKitEventListener?
|
||||||
|
|
||||||
|
public init(listener: JMCallKitEventListener) {
|
||||||
|
self.listener = listener
|
||||||
|
self.hashValue = listener.hash
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: JMCallKitEventListenerWrapper,
|
||||||
|
rhs: JMCallKitEventListenerWrapper) -> Bool {
|
||||||
|
return lhs.hashValue == rhs.hashValue
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* Copyright @ 2018-present Atlassian Pty Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import AVKit
|
||||||
|
import CallKit
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
internal final class JMCallKitNotifier: NSObject, CXProviderDelegate {
|
||||||
|
|
||||||
|
private var listeners = Set<JMCallKitEventListenerWrapper>()
|
||||||
|
|
||||||
|
internal override init() {}
|
||||||
|
|
||||||
|
// MARK: - Add/remove listeners
|
||||||
|
|
||||||
|
func addListener(_ listener: JMCallKitEventListener) {
|
||||||
|
let wrapper = JMCallKitEventListenerWrapper(listener: listener)
|
||||||
|
objc_sync_enter(listeners)
|
||||||
|
listeners.insert(wrapper)
|
||||||
|
objc_sync_exit(listeners)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeListener(_ listener: JMCallKitEventListener) {
|
||||||
|
let wrapper = JMCallKitEventListenerWrapper(listener: listener)
|
||||||
|
objc_sync_enter(listeners)
|
||||||
|
listeners.remove(wrapper)
|
||||||
|
objc_sync_exit(listeners)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - CXProviderDelegate
|
||||||
|
|
||||||
|
func providerDidReset(_ provider: CXProvider) {
|
||||||
|
objc_sync_enter(listeners)
|
||||||
|
listeners.forEach { $0.listener?.providerDidReset?() }
|
||||||
|
objc_sync_exit(listeners)
|
||||||
|
}
|
||||||
|
|
||||||
|
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
||||||
|
objc_sync_enter(listeners)
|
||||||
|
listeners.forEach { $0.listener?.performAnswerCall?(UUID: action.callUUID) }
|
||||||
|
objc_sync_exit(listeners)
|
||||||
|
|
||||||
|
action.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
|
||||||
|
objc_sync_enter(listeners)
|
||||||
|
listeners.forEach { $0.listener?.performEndCall?(UUID: action.callUUID) }
|
||||||
|
objc_sync_exit(listeners)
|
||||||
|
|
||||||
|
action.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {
|
||||||
|
objc_sync_enter(listeners)
|
||||||
|
listeners.forEach {
|
||||||
|
$0.listener?.performSetMutedCall?(UUID: action.callUUID,
|
||||||
|
isMuted: action.isMuted)
|
||||||
|
}
|
||||||
|
objc_sync_exit(listeners)
|
||||||
|
|
||||||
|
action.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
|
||||||
|
objc_sync_enter(listeners)
|
||||||
|
listeners.forEach {
|
||||||
|
$0.listener?.performStartCall?(UUID: action.callUUID,
|
||||||
|
isVideo: action.isVideo)
|
||||||
|
}
|
||||||
|
objc_sync_exit(listeners)
|
||||||
|
|
||||||
|
action.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
|
||||||
|
objc_sync_enter(listeners)
|
||||||
|
listeners.forEach {
|
||||||
|
$0.listener?.providerDidActivateAudioSession?(session: audioSession)
|
||||||
|
}
|
||||||
|
objc_sync_exit(listeners)
|
||||||
|
}
|
||||||
|
|
||||||
|
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
|
||||||
|
objc_sync_enter(listeners)
|
||||||
|
listeners.forEach {
|
||||||
|
$0.listener?.providerDidDeactivateAudioSession?(session: audioSession)
|
||||||
|
}
|
||||||
|
objc_sync_exit(listeners)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
* Copyright @ 2018-present Atlassian Pty Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import CallKit
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// JitsiMeet CallKit proxy
|
||||||
|
@available(iOS 10.0, *)
|
||||||
|
@objc public final class JMCallKitProxy: NSObject {
|
||||||
|
|
||||||
|
override private init() {}
|
||||||
|
|
||||||
|
// MARK: - CallKit proxy
|
||||||
|
|
||||||
|
internal static let cxProvider: CXProvider = {
|
||||||
|
let config = CXProviderConfiguration(localizedName: "")
|
||||||
|
let provider = CXProvider(configuration: config)
|
||||||
|
return provider
|
||||||
|
}()
|
||||||
|
|
||||||
|
internal static let cxCallController: CXCallController = {
|
||||||
|
return CXCallController()
|
||||||
|
}()
|
||||||
|
|
||||||
|
internal static let callKitNotifier: JMCallKitNotifier = {
|
||||||
|
return JMCallKitNotifier()
|
||||||
|
}()
|
||||||
|
|
||||||
|
internal static var cxProviderConfiguration: CXProviderConfiguration? {
|
||||||
|
didSet {
|
||||||
|
guard let providerConfiguration = cxProviderConfiguration else { return }
|
||||||
|
cxProvider.configuration = providerConfiguration
|
||||||
|
cxProvider.setDelegate(callKitNotifier, queue: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables the proxy in between callkit and the consumers of the SDK
|
||||||
|
/// Default to enabled, set to false when you don't want to use callkit
|
||||||
|
@objc public static var enabled: Bool = true {
|
||||||
|
didSet {
|
||||||
|
if enabled == false {
|
||||||
|
cxProvider.setDelegate(nil, queue: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public static func hasProviderBeenConfigurated() -> Bool {
|
||||||
|
return cxProviderConfiguration != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public static func configureCallKitProvider(localizedName: String,
|
||||||
|
ringtoneSound: String?,
|
||||||
|
iconTemplateImageData: Data?) {
|
||||||
|
let configuration = CXProviderConfiguration(localizedName: localizedName)
|
||||||
|
configuration.ringtoneSound = ringtoneSound
|
||||||
|
configuration.iconTemplateImageData = iconTemplateImageData
|
||||||
|
|
||||||
|
configuration.maximumCallGroups = 1
|
||||||
|
configuration.maximumCallsPerCallGroup = 1
|
||||||
|
configuration.supportedHandleTypes = [CXHandle.HandleType.generic]
|
||||||
|
configuration.supportsVideo = true
|
||||||
|
cxProviderConfiguration = configuration
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public static func addListener(_ listener: JMCallKitEventListener) {
|
||||||
|
callKitNotifier.addListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public static func removeListener(_ listener: JMCallKitEventListener) {
|
||||||
|
callKitNotifier.removeListener(listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public static func hasActiveCallForUUID(_ callUUID: String) -> Bool {
|
||||||
|
let activeCallForUUID = cxCallController.callObserver.calls.first {
|
||||||
|
$0.uuid == UUID(uuidString: callUUID)
|
||||||
|
}
|
||||||
|
guard activeCallForUUID != nil else { return false }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public static func reportNewIncomingCall(UUID: UUID,
|
||||||
|
handle: String?,
|
||||||
|
displayName: String?,
|
||||||
|
hasVideo: Bool,
|
||||||
|
completion: @escaping (Error?) -> Void) {
|
||||||
|
guard enabled else { return }
|
||||||
|
|
||||||
|
let callUpdate = makeCXUpdate(handle: handle,
|
||||||
|
displayName: displayName,
|
||||||
|
hasVideo: hasVideo)
|
||||||
|
cxProvider.reportNewIncomingCall(with: UUID,
|
||||||
|
update: callUpdate,
|
||||||
|
completion: completion)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public static func reportCallUpdate(with UUID: UUID,
|
||||||
|
handle: String?,
|
||||||
|
displayName: String?,
|
||||||
|
hasVideo: Bool) {
|
||||||
|
guard enabled else { return }
|
||||||
|
|
||||||
|
let callUpdate = makeCXUpdate(handle: handle,
|
||||||
|
displayName: displayName,
|
||||||
|
hasVideo: hasVideo)
|
||||||
|
cxProvider.reportCall(with: UUID, updated: callUpdate)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public static func reportCall(with UUID: UUID,
|
||||||
|
endedAt dateEnded: Date?,
|
||||||
|
reason endedReason: CXCallEndedReason) {
|
||||||
|
guard enabled else { return }
|
||||||
|
|
||||||
|
cxProvider.reportCall(with: UUID,
|
||||||
|
endedAt: dateEnded,
|
||||||
|
reason: endedReason)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public static func reportOutgoingCall(with UUID: UUID,
|
||||||
|
startedConnectingAt dateStartedConnecting: Date?) {
|
||||||
|
guard enabled else { return }
|
||||||
|
|
||||||
|
cxProvider.reportOutgoingCall(with: UUID,
|
||||||
|
startedConnectingAt: dateStartedConnecting)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public static func reportOutgoingCall(with UUID: UUID,
|
||||||
|
connectedAt dateConnected: Date?) {
|
||||||
|
guard enabled else { return }
|
||||||
|
|
||||||
|
cxProvider.reportOutgoingCall(with: UUID, connectedAt: dateConnected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public static func request(_ transaction: CXTransaction,
|
||||||
|
completion: @escaping (Error?) -> Swift.Void) {
|
||||||
|
guard enabled else { return }
|
||||||
|
|
||||||
|
cxCallController.request(transaction, completion: completion)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Callkit Proxy helpers
|
||||||
|
|
||||||
|
private static func makeCXUpdate(handle: String?,
|
||||||
|
displayName: String?,
|
||||||
|
hasVideo: Bool) -> CXCallUpdate {
|
||||||
|
let update = CXCallUpdate()
|
||||||
|
update.supportsDTMF = false
|
||||||
|
update.supportsHolding = false
|
||||||
|
update.supportsGrouping = false
|
||||||
|
update.supportsUngrouping = false
|
||||||
|
update.hasVideo = hasVideo
|
||||||
|
|
||||||
|
if let handle = handle {
|
||||||
|
update.remoteHandle = CXHandle(type: .generic,
|
||||||
|
value: handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let displayName = displayName {
|
||||||
|
update.localizedCallerName = displayName
|
||||||
|
}
|
||||||
|
|
||||||
|
return update
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ const WHITELISTED_KEYS = [
|
||||||
'callStatsConfIDNamespace',
|
'callStatsConfIDNamespace',
|
||||||
'callStatsID',
|
'callStatsID',
|
||||||
'callStatsSecret',
|
'callStatsSecret',
|
||||||
|
'callUUID',
|
||||||
'channelLastN',
|
'channelLastN',
|
||||||
'constraints',
|
'constraints',
|
||||||
'debug',
|
'debug',
|
||||||
|
|
|
@ -235,10 +235,12 @@ function _conferenceWillJoin({ getState }, next, action) {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const url = getInviteURL(state);
|
const url = getInviteURL(state);
|
||||||
const hasVideo = !isVideoMutedByAudioOnly(state);
|
const hasVideo = !isVideoMutedByAudioOnly(state);
|
||||||
|
const { callUUID } = state['features/base/config'];
|
||||||
|
|
||||||
// When assigning the call UUID, do so in upper case, since iOS will
|
// When assigning the call UUID, do so in upper case, since iOS will
|
||||||
// return it upper cased.
|
// return it upper cased.
|
||||||
conference.callUUID = uuid.v4().toUpperCase();
|
conference.callUUID = (callUUID || uuid.v4()).toUpperCase();
|
||||||
|
|
||||||
CallKit.startCall(conference.callUUID, url.toString(), hasVideo)
|
CallKit.startCall(conference.callUUID, url.toString(), hasVideo)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const { room } = state['features/base/conference'];
|
const { room } = state['features/base/conference'];
|
||||||
|
|
Loading…
Reference in New Issue