mirror of https://github.com/jitsi/jitsi-meet
parent
8c0de928ab
commit
e68ede65e1
@ -1,271 +0,0 @@ |
||||
// IMPORTANT!
|
||||
// This file was once auto-generated by Xcode, and this is a copy of it. If any of the following
|
||||
// classes is modified this file needs to be regenerated.
|
||||
// - JMCallKitListener
|
||||
// - JMCallKitProxy
|
||||
#ifndef JITSIMEETSDK_SWIFT_H |
||||
#define JITSIMEETSDK_SWIFT_H |
||||
#pragma clang diagnostic push |
||||
#pragma clang diagnostic ignored "-Wgcc-compat" |
||||
|
||||
#if !defined(__has_include) |
||||
# define __has_include(x) 0 |
||||
#endif |
||||
#if !defined(__has_attribute) |
||||
# define __has_attribute(x) 0 |
||||
#endif |
||||
#if !defined(__has_feature) |
||||
# define __has_feature(x) 0 |
||||
#endif |
||||
#if !defined(__has_warning) |
||||
# define __has_warning(x) 0 |
||||
#endif |
||||
|
||||
#if __has_include(<swift/objc-prologue.h>) |
||||
# include <swift/objc-prologue.h> |
||||
#endif |
||||
|
||||
#pragma clang diagnostic ignored "-Wauto-import" |
||||
#include <Foundation/Foundation.h> |
||||
#include <stdint.h> |
||||
#include <stddef.h> |
||||
#include <stdbool.h> |
||||
|
||||
#if !defined(SWIFT_TYPEDEFS) |
||||
# define SWIFT_TYPEDEFS 1 |
||||
# if __has_include(<uchar.h>) |
||||
# include <uchar.h> |
||||
# elif !defined(__cplusplus) |
||||
typedef uint_least16_t char16_t; |
||||
typedef uint_least32_t char32_t; |
||||
# endif |
||||
typedef float swift_float2 __attribute__((__ext_vector_type__(2))); |
||||
typedef float swift_float3 __attribute__((__ext_vector_type__(3))); |
||||
typedef float swift_float4 __attribute__((__ext_vector_type__(4))); |
||||
typedef double swift_double2 __attribute__((__ext_vector_type__(2))); |
||||
typedef double swift_double3 __attribute__((__ext_vector_type__(3))); |
||||
typedef double swift_double4 __attribute__((__ext_vector_type__(4))); |
||||
typedef int swift_int2 __attribute__((__ext_vector_type__(2))); |
||||
typedef int swift_int3 __attribute__((__ext_vector_type__(3))); |
||||
typedef int swift_int4 __attribute__((__ext_vector_type__(4))); |
||||
typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); |
||||
typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); |
||||
typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); |
||||
#endif |
||||
|
||||
#if !defined(SWIFT_PASTE) |
||||
# define SWIFT_PASTE_HELPER(x, y) x##y |
||||
# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) |
||||
#endif |
||||
#if !defined(SWIFT_METATYPE) |
||||
# define SWIFT_METATYPE(X) Class |
||||
#endif |
||||
#if !defined(SWIFT_CLASS_PROPERTY) |
||||
# if __has_feature(objc_class_property) |
||||
# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ |
||||
# else |
||||
# define SWIFT_CLASS_PROPERTY(...) |
||||
# endif |
||||
#endif |
||||
|
||||
#if __has_attribute(objc_runtime_name) |
||||
# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) |
||||
#else |
||||
# define SWIFT_RUNTIME_NAME(X) |
||||
#endif |
||||
#if __has_attribute(swift_name) |
||||
# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) |
||||
#else |
||||
# define SWIFT_COMPILE_NAME(X) |
||||
#endif |
||||
#if __has_attribute(objc_method_family) |
||||
# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) |
||||
#else |
||||
# define SWIFT_METHOD_FAMILY(X) |
||||
#endif |
||||
#if __has_attribute(noescape) |
||||
# define SWIFT_NOESCAPE __attribute__((noescape)) |
||||
#else |
||||
# define SWIFT_NOESCAPE |
||||
#endif |
||||
#if __has_attribute(ns_consumed) |
||||
# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) |
||||
#else |
||||
# define SWIFT_RELEASES_ARGUMENT |
||||
#endif |
||||
#if __has_attribute(warn_unused_result) |
||||
# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) |
||||
#else |
||||
# define SWIFT_WARN_UNUSED_RESULT |
||||
#endif |
||||
#if __has_attribute(noreturn) |
||||
# define SWIFT_NORETURN __attribute__((noreturn)) |
||||
#else |
||||
# define SWIFT_NORETURN |
||||
#endif |
||||
#if !defined(SWIFT_CLASS_EXTRA) |
||||
# define SWIFT_CLASS_EXTRA |
||||
#endif |
||||
#if !defined(SWIFT_PROTOCOL_EXTRA) |
||||
# define SWIFT_PROTOCOL_EXTRA |
||||
#endif |
||||
#if !defined(SWIFT_ENUM_EXTRA) |
||||
# define SWIFT_ENUM_EXTRA |
||||
#endif |
||||
#if !defined(SWIFT_CLASS) |
||||
# if __has_attribute(objc_subclassing_restricted) |
||||
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA |
||||
# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA |
||||
# else |
||||
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA |
||||
# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA |
||||
# endif |
||||
#endif |
||||
#if !defined(SWIFT_RESILIENT_CLASS) |
||||
# if __has_attribute(objc_class_stub) |
||||
# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) |
||||
# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) |
||||
# else |
||||
# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) |
||||
# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) |
||||
# endif |
||||
#endif |
||||
|
||||
#if !defined(SWIFT_PROTOCOL) |
||||
# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA |
||||
# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA |
||||
#endif |
||||
|
||||
#if !defined(SWIFT_EXTENSION) |
||||
# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) |
||||
#endif |
||||
|
||||
#if !defined(OBJC_DESIGNATED_INITIALIZER) |
||||
# if __has_attribute(objc_designated_initializer) |
||||
# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) |
||||
# else |
||||
# define OBJC_DESIGNATED_INITIALIZER |
||||
# endif |
||||
#endif |
||||
#if !defined(SWIFT_ENUM_ATTR) |
||||
# if defined(__has_attribute) && __has_attribute(enum_extensibility) |
||||
# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) |
||||
# else |
||||
# define SWIFT_ENUM_ATTR(_extensibility) |
||||
# endif |
||||
#endif |
||||
#if !defined(SWIFT_ENUM) |
||||
# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type |
||||
# if __has_feature(generalized_swift_name) |
||||
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type |
||||
# else |
||||
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) |
||||
# endif |
||||
#endif |
||||
#if !defined(SWIFT_UNAVAILABLE) |
||||
# define SWIFT_UNAVAILABLE __attribute__((unavailable)) |
||||
#endif |
||||
#if !defined(SWIFT_UNAVAILABLE_MSG) |
||||
# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) |
||||
#endif |
||||
#if !defined(SWIFT_AVAILABILITY) |
||||
# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) |
||||
#endif |
||||
#if !defined(SWIFT_WEAK_IMPORT) |
||||
# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) |
||||
#endif |
||||
#if !defined(SWIFT_DEPRECATED) |
||||
# define SWIFT_DEPRECATED __attribute__((deprecated)) |
||||
#endif |
||||
#if !defined(SWIFT_DEPRECATED_MSG) |
||||
# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) |
||||
#endif |
||||
#if __has_feature(attribute_diagnose_if_objc) |
||||
# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) |
||||
#else |
||||
# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) |
||||
#endif |
||||
#if !defined(IBSegueAction) |
||||
# define IBSegueAction |
||||
#endif |
||||
#if !defined(SWIFT_EXTERN) |
||||
# if defined(__cplusplus) |
||||
# define SWIFT_EXTERN extern "C" |
||||
# else |
||||
# define SWIFT_EXTERN extern |
||||
# endif |
||||
#endif |
||||
#if __has_feature(modules) |
||||
#if __has_warning("-Watimport-in-framework-header") |
||||
#pragma clang diagnostic ignored "-Watimport-in-framework-header" |
||||
#endif |
||||
@import CallKit; |
||||
@import ObjectiveC; |
||||
#endif |
||||
|
||||
#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" |
||||
#pragma clang diagnostic ignored "-Wduplicate-method-arg" |
||||
#if __has_warning("-Wpragma-clang-attribute") |
||||
# pragma clang diagnostic ignored "-Wpragma-clang-attribute" |
||||
#endif |
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas" |
||||
#pragma clang diagnostic ignored "-Wnullability" |
||||
|
||||
#if __has_attribute(external_source_symbol) |
||||
# pragma push_macro("any") |
||||
# undef any |
||||
# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="JitsiMeetSDK",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) |
||||
# pragma pop_macro("any") |
||||
#endif |
||||
|
||||
|
||||
|
||||
@class NSUUID; |
||||
@class AVAudioSession; |
||||
@class CXAction; |
||||
|
||||
SWIFT_PROTOCOL("_TtP12JitsiMeetSDK17JMCallKitListener_") |
||||
@protocol JMCallKitListener <NSObject> |
||||
@optional |
||||
- (void)providerDidReset; |
||||
- (void)performAnswerCallWithUUID:(NSUUID * _Nonnull)UUID; |
||||
- (void)performEndCallWithUUID:(NSUUID * _Nonnull)UUID; |
||||
- (void)performSetMutedCallWithUUID:(NSUUID * _Nonnull)UUID isMuted:(BOOL)isMuted; |
||||
- (void)performStartCallWithUUID:(NSUUID * _Nonnull)UUID isVideo:(BOOL)isVideo; |
||||
- (void)providerDidActivateAudioSessionWithSession:(AVAudioSession * _Nonnull)session; |
||||
- (void)providerDidDeactivateAudioSessionWithSession:(AVAudioSession * _Nonnull)session; |
||||
- (void)providerTimedOutPerformingActionWithAction:(CXAction * _Nonnull)action; |
||||
@end |
||||
|
||||
@class NSString; |
||||
@class NSData; |
||||
@class NSDate; |
||||
@class CXTransaction; |
||||
|
||||
SWIFT_CLASS("_TtC12JitsiMeetSDK14JMCallKitProxy") |
||||
@interface JMCallKitProxy : NSObject |
||||
- (nonnull instancetype)init SWIFT_UNAVAILABLE; |
||||
+ (nonnull instancetype)new SWIFT_UNAVAILABLE_MSG("-init is unavailable"); |
||||
/// Enables the proxy in between CallKit and the consumers of the SDK.
|
||||
/// Defaults to disabled. Set to true when you want to use CallKit.
|
||||
SWIFT_CLASS_PROPERTY(@property (nonatomic, class) BOOL enabled;) |
||||
+ (BOOL)enabled SWIFT_WARN_UNUSED_RESULT; |
||||
+ (void)setEnabled:(BOOL)value; |
||||
+ (void)configureProviderWithLocalizedName:(NSString * _Nonnull)localizedName ringtoneSound:(NSString * _Nullable)ringtoneSound iconTemplateImageData:(NSData * _Nullable)iconTemplateImageData; |
||||
+ (BOOL)isProviderConfigured SWIFT_WARN_UNUSED_RESULT; |
||||
+ (void)addListener:(id <JMCallKitListener> _Nonnull)listener; |
||||
+ (void)removeListener:(id <JMCallKitListener> _Nonnull)listener; |
||||
+ (BOOL)hasActiveCallForUUID:(NSString * _Nonnull)callUUID SWIFT_WARN_UNUSED_RESULT; |
||||
+ (void)reportNewIncomingCallWithUUID:(NSUUID * _Nonnull)UUID handle:(NSString * _Nullable)handle displayName:(NSString * _Nullable)displayName hasVideo:(BOOL)hasVideo completion:(void (^ _Nonnull)(NSError * _Nullable))completion; |
||||
+ (void)reportCallUpdateWith:(NSUUID * _Nonnull)UUID handle:(NSString * _Nullable)handle displayName:(NSString * _Nullable)displayName hasVideo:(BOOL)hasVideo; |
||||
+ (void)reportCallWith:(NSUUID * _Nonnull)UUID endedAt:(NSDate * _Nullable)dateEnded reason:(CXCallEndedReason)endedReason; |
||||
+ (void)reportOutgoingCallWith:(NSUUID * _Nonnull)UUID startedConnectingAt:(NSDate * _Nullable)dateStartedConnecting; |
||||
+ (void)reportOutgoingCallWith:(NSUUID * _Nonnull)UUID connectedAt:(NSDate * _Nullable)dateConnected; |
||||
+ (void)request:(CXTransaction * _Nonnull)transaction completion:(void (^ _Nonnull)(NSError * _Nullable))completion; |
||||
@end |
||||
|
||||
#if __has_attribute(external_source_symbol) |
||||
# pragma clang attribute pop |
||||
#endif |
||||
#pragma clang diagnostic pop |
||||
#endif |
@ -0,0 +1,35 @@ |
||||
/*
|
||||
* Copyright @ 2022-present 8x8, Inc. |
||||
* 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/CallKit.h> |
||||
#import <Foundation/Foundation.h> |
||||
#import "JMCallKitListener.h" |
||||
|
||||
NS_ASSUME_NONNULL_BEGIN |
||||
|
||||
@interface JMCallKitEmitter : NSObject <CXProviderDelegate> |
||||
|
||||
#pragma mark Add/Remove listeners |
||||
- (void)addListener:(id<JMCallKitListener>)listener; |
||||
- (void)removeListener:(id<JMCallKitListener>)listener; |
||||
|
||||
#pragma mark Add mute action |
||||
- (void)addMuteAction:(NSUUID *)actionUUID; |
||||
|
||||
@end |
||||
|
||||
NS_ASSUME_NONNULL_END |
@ -0,0 +1,116 @@ |
||||
/* |
||||
* Copyright @ 2022-present 8x8, Inc. |
||||
* 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 "JMCallKitEmitter.h" |
||||
|
||||
@interface JMCallKitEmitter() |
||||
|
||||
@property(nonatomic, strong) NSMutableArray<id<JMCallKitListener>> *listeners; |
||||
@property(nonatomic, strong) NSMutableSet<NSUUID *> *pendingMuteActions; |
||||
|
||||
@end |
||||
|
||||
@implementation JMCallKitEmitter |
||||
|
||||
- (instancetype)init { |
||||
self = [super init]; |
||||
if (self) { |
||||
self.listeners = [[NSMutableArray alloc] init]; |
||||
self.pendingMuteActions = [[NSMutableSet alloc] init]; |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
#pragma mark Add/Remove listeners |
||||
|
||||
- (void)addListener:(id<JMCallKitListener>)listener { |
||||
if (![self.listeners containsObject:listener]) { |
||||
[self.listeners addObject:listener]; |
||||
} |
||||
} |
||||
|
||||
- (void)removeListener:(id<JMCallKitListener>)listener { |
||||
[self.listeners removeObject:listener]; |
||||
} |
||||
|
||||
#pragma mark Add mute action |
||||
|
||||
- (void)addMuteAction:(NSUUID *)actionUUID { |
||||
[self.pendingMuteActions addObject:actionUUID]; |
||||
} |
||||
|
||||
#pragma mark CXProviderDelegate |
||||
|
||||
- (void)providerDidReset:(CXProvider *)provider { |
||||
for (id listener in self.listeners) { |
||||
[listener providerDidReset]; |
||||
} |
||||
[self.pendingMuteActions removeAllObjects]; |
||||
} |
||||
|
||||
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action { |
||||
for (id listener in self.listeners) { |
||||
[listener performAnswerCallWithUUID:action.callUUID]; |
||||
} |
||||
[action fulfill]; |
||||
} |
||||
|
||||
- (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action { |
||||
for (id listener in self.listeners) { |
||||
[listener performEndCallWithUUID:action.callUUID]; |
||||
} |
||||
[action fulfill]; |
||||
} |
||||
|
||||
- (void)provider:(CXProvider *)provider performSetMutedCallAction:(CXSetMutedCallAction *)action { |
||||
NSUUID *uuid = ([self.pendingMuteActions containsObject:action.UUID]) ? action.UUID : nil; |
||||
[self.pendingMuteActions removeObject:action.UUID]; |
||||
|
||||
// Avoid mute actions ping-pong: if the mute action was caused by |
||||
// the JS side (we requested a transaction) don't call the delegate |
||||
// method. If it was called by the provider itself (when the user presses |
||||
// the mute button in the CallKit view) then call the delegate method. |
||||
// |
||||
// NOTE: don't try to be clever and remove this. Been there, done that. |
||||
// Won't work. |
||||
if (uuid == nil) { |
||||
for (id listener in self.listeners) { |
||||
[listener performSetMutedCallWithUUID:action.callUUID isMuted:action.isMuted]; |
||||
} |
||||
} |
||||
[action fulfill]; |
||||
} |
||||
|
||||
- (void)provider:(CXProvider *)provider performStartCallAction:(CXStartCallAction *)action { |
||||
for (id listener in self.listeners) { |
||||
[listener performStartCallWithUUID:action.callUUID isVideo:action.isVideo]; |
||||
} |
||||
} |
||||
|
||||
- (void)provider:(CXProvider *)provider didActivateAudioSession:(AVAudioSession *)audioSession { |
||||
for (id listener in self.listeners) { |
||||
[listener providerDidActivateAudioSessionWithSession:audioSession]; |
||||
} |
||||
} |
||||
|
||||
- (void)provider:(CXProvider *)provider didDeactivateAudioSession:(AVAudioSession *)audioSession { |
||||
for (id listener in self.listeners) { |
||||
[listener providerDidDeactivateAudioSessionWithSession:audioSession]; |
||||
} |
||||
} |
||||
|
||||
@end |
@ -1,118 +0,0 @@ |
||||
/* |
||||
* 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 JMCallKitEmitter: NSObject, CXProviderDelegate { |
||||
|
||||
private let listeners = NSMutableArray() |
||||
private var pendingMuteActions = Set<UUID>() |
||||
|
||||
internal override init() {} |
||||
|
||||
// MARK: - Add/remove listeners |
||||
|
||||
func addListener(_ listener: JMCallKitListener) { |
||||
if (!listeners.contains(listener)) { |
||||
listeners.add(listener) |
||||
} |
||||
} |
||||
|
||||
func removeListener(_ listener: JMCallKitListener) { |
||||
listeners.remove(listener) |
||||
} |
||||
|
||||
// MARK: - Add mute action |
||||
|
||||
func addMuteAction(_ actionUUID: UUID) { |
||||
pendingMuteActions.insert(actionUUID) |
||||
} |
||||
|
||||
// MARK: - CXProviderDelegate |
||||
|
||||
func providerDidReset(_ provider: CXProvider) { |
||||
listeners.forEach { |
||||
let listener = $0 as! JMCallKitListener |
||||
listener.providerDidReset?() |
||||
} |
||||
pendingMuteActions.removeAll() |
||||
} |
||||
|
||||
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) { |
||||
listeners.forEach { |
||||
let listener = $0 as! JMCallKitListener |
||||
listener.performAnswerCall?(UUID: action.callUUID) |
||||
} |
||||
|
||||
action.fulfill() |
||||
} |
||||
|
||||
func provider(_ provider: CXProvider, perform action: CXEndCallAction) { |
||||
listeners.forEach { |
||||
let listener = $0 as! JMCallKitListener |
||||
listener.performEndCall?(UUID: action.callUUID) |
||||
} |
||||
|
||||
action.fulfill() |
||||
} |
||||
|
||||
func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) { |
||||
let uuid = pendingMuteActions.remove(action.uuid) |
||||
|
||||
// Avoid mute actions ping-pong: if the mute action was caused by |
||||
// the JS side (we requested a transaction) don't call the delegate |
||||
// method. If it was called by the provider itself (when the user presses |
||||
// the mute button in the CallKit view) then call the delegate method. |
||||
// |
||||
// NOTE: don't try to be clever and remove this. Been there, done that. |
||||
// Won't work. |
||||
if (uuid == nil) { |
||||
listeners.forEach { |
||||
let listener = $0 as! JMCallKitListener |
||||
listener.performSetMutedCall?(UUID: action.callUUID, isMuted: action.isMuted) |
||||
} |
||||
} |
||||
|
||||
action.fulfill() |
||||
} |
||||
|
||||
func provider(_ provider: CXProvider, perform action: CXStartCallAction) { |
||||
listeners.forEach { |
||||
let listener = $0 as! JMCallKitListener |
||||
listener.performStartCall?(UUID: action.callUUID, isVideo: action.isVideo) |
||||
} |
||||
|
||||
action.fulfill() |
||||
} |
||||
|
||||
func provider(_ provider: CXProvider, |
||||
didActivate audioSession: AVAudioSession) { |
||||
listeners.forEach { |
||||
let listener = $0 as! JMCallKitListener |
||||
listener.providerDidActivateAudioSession?(session: audioSession) |
||||
} |
||||
} |
||||
|
||||
func provider(_ provider: CXProvider, |
||||
didDeactivate audioSession: AVAudioSession) { |
||||
listeners.forEach { |
||||
let listener = $0 as! JMCallKitListener |
||||
listener.providerDidDeactivateAudioSession?(session: audioSession) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,34 @@ |
||||
/*
|
||||
* Copyright @ 2022-present 8x8, Inc. |
||||
* 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/AVKit.h> |
||||
#import <CallKit/CallKit.h> |
||||
#import <Foundation/Foundation.h> |
||||
|
||||
@protocol JMCallKitListener <NSObject> |
||||
|
||||
@optional |
||||
- (void)providerDidReset; |
||||
- (void)performAnswerCallWithUUID:(nonnull NSUUID *)UUID; |
||||
- (void)performEndCallWithUUID:(nonnull NSUUID *)UUID; |
||||
- (void)performSetMutedCallWithUUID:(nonnull NSUUID *)UUID isMuted:(BOOL)isMuted; |
||||
- (void)performStartCallWithUUID:(nonnull NSUUID *)UUID isVideo:(BOOL)isVideo; |
||||
- (void)providerDidActivateAudioSessionWithSession:(nonnull AVAudioSession *)session; |
||||
- (void)providerDidDeactivateAudioSessionWithSession:(nonnull AVAudioSession *)session; |
||||
- (void)providerTimedOutPerformingActionWithAction:(nonnull CXAction *)action; |
||||
|
||||
@end |
@ -1,38 +0,0 @@ |
||||
/* |
||||
* 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 JMCallKitListener: NSObjectProtocol { |
||||
|
||||
@objc optional func providerDidReset() |
||||
|
||||
@objc optional func performAnswerCall(UUID: UUID) |
||||
|
||||
@objc optional func performEndCall(UUID: UUID) |
||||
|
||||
@objc optional func performSetMutedCall(UUID: UUID, isMuted: Bool) |
||||
|
||||
@objc optional func performStartCall(UUID: UUID, isVideo: Bool) |
||||
|
||||
@objc optional func providerDidActivateAudioSession(session: AVAudioSession) |
||||
|
||||
@objc optional func providerDidDeactivateAudioSession(session: AVAudioSession) |
||||
|
||||
@objc optional func providerTimedOutPerformingAction(action: CXAction) |
||||
} |
@ -0,0 +1,87 @@ |
||||
/*
|
||||
* Copyright @ 2022-present 8x8, Inc. |
||||
* 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/CallKit.h> |
||||
#import <Foundation/Foundation.h> |
||||
#import "JMCallKitListener.h" |
||||
|
||||
NS_ASSUME_NONNULL_BEGIN |
||||
|
||||
@protocol CXProviderProtocol <NSObject> |
||||
|
||||
@property (nonatomic, readwrite, copy) CXProviderConfiguration* configuration; |
||||
|
||||
- (void)setDelegate:(nullable id<CXProviderDelegate>)delegate queue:(nullable dispatch_queue_t)queue; |
||||
- (void)reportNewIncomingCallWithUUID:(NSUUID *)uuid update:(CXCallUpdate *)update completion:(void (^)(NSError *))completion; |
||||
- (void)reportCallWithUUID:(NSUUID *)uuid updated:(CXCallUpdate *)update; |
||||
- (void)reportCallWithUUID:(NSUUID *)uuid endedAtDate:(NSDate *)dateEnded reason:(CXCallEndedReason)endedReason; |
||||
- (void)reportOutgoingCallWithUUID:(NSUUID *)uuid startedConnectingAtDate:(NSDate *)dateStartedConnecting; |
||||
- (void)reportOutgoingCallWithUUID:(NSUUID *)uuid connectedAtDate:(NSDate *)dateConnected; |
||||
- (void)invalidate; |
||||
|
||||
@end |
||||
|
||||
#pragma mark - |
||||
@protocol CXCallControllerProtocol <NSObject> |
||||
|
||||
@property (nonatomic, readonly) NSArray<CXCall*> *calls; |
||||
|
||||
- (void)requestTransaction:(CXTransaction *)transaction completion:(void (^)(NSError *_Nullable))completion; |
||||
|
||||
@end |
||||
|
||||
#pragma mark - |
||||
|
||||
/// JitsiMeet CallKit proxy
|
||||
// NOTE: The methods this class exposes are meant to be called in the UI thread.
|
||||
// All delegate methods called by JMCallKitEmitter will be called in the UI thread.
|
||||
@interface JMCallKitProxy : NSObject |
||||
|
||||
/// Enables the proxy in between CallKit and the consumers of the SDK.
|
||||
/// Defaults to disabled. Set to true when you want to use CallKit.
|
||||
@property (class) BOOL enabled; |
||||
@property (class) id<CXProviderProtocol> callKitProvider; |
||||
@property (class) id<CXCallControllerProtocol> callKitCallController; |
||||
|
||||
+ (void)configureProviderWithLocalizedName:(nonnull NSString *)localizedName |
||||
ringtoneSound:(nullable NSString *)ringtoneSound |
||||
iconTemplateImageData:(nullable NSData*)imageData |
||||
NS_SWIFT_NAME(configureProvider(localizedName:ringtoneSound:iconTemplateImageData:)); |
||||
+ (BOOL)isProviderConfigured; |
||||
+ (void)addListener:(nonnull id<JMCallKitListener>)listener NS_SWIFT_NAME(addListener(_:)); |
||||
+ (void)removeListener:(nonnull id<JMCallKitListener>)listener NS_SWIFT_NAME(removeListener(_:)); |
||||
+ (BOOL)hasActiveCallForUUID:(nonnull NSString *)callUUID NS_SWIFT_NAME(hasActiveCallForUUID(_:)); |
||||
+ (void)reportNewIncomingCallWithUUID:(nonnull NSUUID *)uuid |
||||
handle:(nullable NSString*)handle |
||||
displayName:(nullable NSString*)displayName |
||||
hasVideo:(BOOL)hasVideo |
||||
completion:(nonnull void (^)(NSError *_Nullable))completion |
||||
NS_SWIFT_NAME(reportNewIncomingCall(UUID:handle:displayName:hasVideo:completion:)); |
||||
+ (void)reportCallUpdateWith:(nonnull NSUUID *)uuid |
||||
handle:(nullable NSString *)handle |
||||
displayName:(nullable NSString *)displayName |
||||
hasVideo:(BOOL)hasVideo; |
||||
+ (void)reportCallWith:(nonnull NSUUID *)uuid |
||||
endedAt:(nullable NSDate *)dateEnded |
||||
reason:(CXCallEndedReason)endedReason; |
||||
+ (void)reportOutgoingCallWith:(nonnull NSUUID *)uuid startedConnectingAt:(nullable NSDate *)dateStartedConnecting; |
||||
+ (void)reportOutgoingCallWith:(nonnull NSUUID *)uuid connectedAt:(nullable NSDate *)dateConnected; |
||||
+ (void)request:(nonnull CXTransaction *)transaction completion:(nonnull void (^)(NSError *_Nullable))completion; |
||||
|
||||
@end |
||||
|
||||
NS_ASSUME_NONNULL_END |
@ -0,0 +1,284 @@ |
||||
/* |
||||
* Copyright @ 2022-present 8x8, Inc. |
||||
* 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 "JMCallKitProxy.h" |
||||
#import "JMCallKitEmitter.h" |
||||
|
||||
#pragma mark - |
||||
@interface CXProvider(CXProviderProtocol) <CXProviderProtocol> |
||||
@end |
||||
|
||||
@implementation CXProvider(CXProviderProtocol) |
||||
@end |
||||
|
||||
#pragma mark - |
||||
@interface CXCallController(CXCallControllerProtocol) <CXCallControllerProtocol> |
||||
|
||||
@property (nonatomic, readonly) NSArray<CXCall*> *calls; |
||||
|
||||
@end |
||||
|
||||
@implementation CXCallController(CXCallControllerProtocol) |
||||
|
||||
@dynamic calls; |
||||
|
||||
- (NSArray<CXCall*> *)calls { |
||||
return self.callObserver.calls; |
||||
} |
||||
|
||||
@end |
||||
|
||||
#pragma mark - |
||||
@interface JMCallKitProxy () |
||||
|
||||
@property (class) CXProvider *defaultProvider; |
||||
@property (class) CXProviderConfiguration *providerConfiguration; |
||||
|
||||
@end |
||||
|
||||
@interface JMCallKitProxy (Helpers) |
||||
|
||||
+ (CXCallUpdate *)makeCXUpdateWithHandle:(nullable NSString *)handle displayName:(nullable NSString *)displayName hasVideo:(BOOL)hasVideo; |
||||
|
||||
@end |
||||
|
||||
@implementation JMCallKitProxy |
||||
|
||||
@dynamic callKitProvider, callKitCallController, enabled; |
||||
@dynamic defaultProvider, providerConfiguration; |
||||
|
||||
static id<CXProviderProtocol> _callKitProvider = nil; |
||||
static id<CXCallControllerProtocol> _callKitCallController = nil; |
||||
static BOOL _enabled = false; |
||||
static CXProvider *_defaultProvider = nil; |
||||
static CXProviderConfiguration *_providerConfiguration = nil; |
||||
|
||||
#pragma mark CallJit proxy |
||||
|
||||
+ (id<CXProviderProtocol>)callKitProvider { |
||||
return _callKitProvider; |
||||
} |
||||
|
||||
+ (void)setCallKitProvider:(id<CXProviderProtocol>)callKitProvider { |
||||
if (_callKitProvider != callKitProvider) { |
||||
_callKitProvider = callKitProvider; |
||||
} |
||||
} |
||||
|
||||
+ (id<CXCallControllerProtocol>)callKitCallController { |
||||
return _callKitCallController; |
||||
} |
||||
|
||||
+ (void)setCallKitCallController:(id<CXCallControllerProtocol>)callKitCallController { |
||||
if (_callKitCallController != callKitCallController) { |
||||
_callKitCallController = callKitCallController; |
||||
} |
||||
} |
||||
|
||||
+ (BOOL)enabled { |
||||
return _enabled; |
||||
} |
||||
|
||||
+ (void)setEnabled:(BOOL)enabled { |
||||
_enabled = enabled ; |
||||
|
||||
if (!self.callKitProvider) { |
||||
[self.provider invalidate]; |
||||
} |
||||
|
||||
if (enabled) { |
||||
CXProviderConfiguration *configuration = self.providerConfiguration? self.providerConfiguration : [[CXProviderConfiguration alloc] initWithLocalizedName:@""]; |
||||
if (!self.callKitProvider) { |
||||
self.defaultProvider = [[CXProvider alloc] initWithConfiguration: configuration]; |
||||
} |
||||
|
||||
[self.provider setDelegate:self.emitter queue:nil]; |
||||
} else { |
||||
[self.provider setDelegate:nil queue:nil]; |
||||
} |
||||
} |
||||
|
||||
+ (CXProvider *)defaultProvider { |
||||
return _defaultProvider; |
||||
} |
||||
|
||||
+ (void)setDefaultProvider:(CXProvider *)defaultProvider { |
||||
if (_defaultProvider != defaultProvider) { |
||||
_defaultProvider = defaultProvider; |
||||
} |
||||
} |
||||
|
||||
+ (id<CXProviderProtocol>)provider { |
||||
return self.callKitProvider != nil ? self.callKitProvider : self.defaultProvider; |
||||
} |
||||
|
||||
+ (id<CXCallControllerProtocol>)callController { |
||||
return self.callKitCallController != nil ? self.callKitCallController : self.defaultCallController; |
||||
} |
||||
|
||||
+ (CXProviderConfiguration *)providerConfiguration { |
||||
return _providerConfiguration; |
||||
} |
||||
|
||||
+ (void)setProviderConfiguration:(CXProviderConfiguration *)providerConfiguration { |
||||
if (_providerConfiguration != providerConfiguration) { |
||||
_providerConfiguration = providerConfiguration; |
||||
|
||||
if (providerConfiguration) { |
||||
self.provider.configuration = providerConfiguration; |
||||
[self.provider setDelegate:self.emitter queue:nil]; |
||||
} |
||||
} |
||||
} |
||||
|
||||
+ (CXCallController *)defaultCallController { |
||||
static dispatch_once_t once; |
||||
static CXCallController *defaultCallController; |
||||
dispatch_once(&once, ^{ |
||||
defaultCallController = [[CXCallController alloc] init]; |
||||
}); |
||||
|
||||
return defaultCallController; |
||||
} |
||||
|
||||
+ (JMCallKitEmitter *)emitter { |
||||
static dispatch_once_t once; |
||||
static JMCallKitEmitter *emitter; |
||||
dispatch_once(&once, ^{ |
||||
emitter = [[JMCallKitEmitter alloc] init]; |
||||
}); |
||||
|
||||
return emitter; |
||||
} |
||||
|
||||
+ (void)configureProviderWithLocalizedName:(nonnull NSString *)localizedName |
||||
ringtoneSound:(nullable NSString *)ringtoneSound |
||||
iconTemplateImageData:(nullable NSData*)imageData { |
||||
if (!self.enabled) { |
||||
return; |
||||
} |
||||
|
||||
CXProviderConfiguration *configuration = [[CXProviderConfiguration alloc] initWithLocalizedName:localizedName]; |
||||
configuration.iconTemplateImageData = imageData; |
||||
configuration.maximumCallGroups = 1; |
||||
configuration.maximumCallsPerCallGroup = 1; |
||||
configuration.ringtoneSound = ringtoneSound; |
||||
configuration.supportedHandleTypes = [NSSet setWithArray:@[@(CXHandleTypeGeneric)]]; |
||||
configuration.supportsVideo = true; |
||||
|
||||
self.providerConfiguration = configuration; |
||||
} |
||||
|
||||
+ (BOOL)isProviderConfigured { |
||||
return self.providerConfiguration != nil; |
||||
} |
||||
|
||||
+ (void)addListener:(nonnull id<JMCallKitListener>)listener { |
||||
[self.emitter addListener:listener]; |
||||
} |
||||
|
||||
+ (void)removeListener:(nonnull id<JMCallKitListener>)listener { |
||||
[self.emitter removeListener:listener]; |
||||
} |
||||
|
||||
+ (BOOL)hasActiveCallForUUID:(nonnull NSString *)callUUID { |
||||
CXCall *activeCallForUUID = [[self.callController calls] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(CXCall *evaluatedObject, NSDictionary<NSString *,id> *bindings) { |
||||
return evaluatedObject.UUID.UUIDString == callUUID; |
||||
}]].firstObject; |
||||
|
||||
if (!activeCallForUUID) { |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
+ (void)reportNewIncomingCallWithUUID:(nonnull NSUUID *)uuid |
||||
handle:(nullable NSString*)handle |
||||
displayName:(nullable NSString*)displayName |
||||
hasVideo:(BOOL)hasVideo |
||||
completion:(nonnull void (^)(NSError *_Nullable))completion { |
||||
if (!self.enabled) { |
||||
return; |
||||
} |
||||
|
||||
CXCallUpdate *callUpdate = [self makeCXUpdateWithHandle:handle displayName:displayName hasVideo:hasVideo]; |
||||
[self.provider reportNewIncomingCallWithUUID:uuid update:callUpdate completion:completion]; |
||||
} |
||||
|
||||
+ (void)reportCallUpdateWith:(nonnull NSUUID *)uuid |
||||
handle:(nullable NSString *)handle |
||||
displayName:(nullable NSString *)displayName |
||||
hasVideo:(BOOL)hasVideo { |
||||
if (!self.enabled) { |
||||
return; |
||||
} |
||||
|
||||
CXCallUpdate *callUpdate = [self makeCXUpdateWithHandle:handle displayName:displayName hasVideo:hasVideo]; |
||||
[self.provider reportCallWithUUID:uuid updated:callUpdate]; |
||||
} |
||||
|
||||
+ (void)reportCallWith:(nonnull NSUUID *)uuid |
||||
endedAt:(nullable NSDate *)dateEnded |
||||
reason:(CXCallEndedReason)endedReason { |
||||
[self.provider reportCallWithUUID:uuid endedAtDate:dateEnded reason:endedReason]; |
||||
} |
||||
|
||||
+ (void)reportOutgoingCallWith:(nonnull NSUUID *)uuid startedConnectingAt:(nullable NSDate *)dateStartedConnecting { |
||||
[self.provider reportOutgoingCallWithUUID:uuid startedConnectingAtDate:dateStartedConnecting]; |
||||
} |
||||
|
||||
+ (void)reportOutgoingCallWith:(nonnull NSUUID *)uuid connectedAt:(nullable NSDate *)dateConnected { |
||||
[self.provider reportOutgoingCallWithUUID:uuid connectedAtDate:dateConnected]; |
||||
} |
||||
|
||||
+ (void)request:(nonnull CXTransaction *)transaction completion:(nonnull void (^)(NSError *_Nullable))completion { |
||||
if (!self.enabled) { |
||||
return; |
||||
} |
||||
|
||||
// XXX keep track of muted actions to avoid "ping-pong"ing. See |
||||
// JMCallKitEmitter for details on the CXSetMutedCallAction handling. |
||||
for (CXAction *action in transaction.actions) { |
||||
if ([CXAction isKindOfClass:[CXSetMutedCallAction class]]) { |
||||
[self.emitter addMuteAction:action.UUID]; |
||||
} |
||||
} |
||||
|
||||
[self.callController requestTransaction:transaction completion:completion]; |
||||
} |
||||
|
||||
@end |
||||
|
||||
@implementation JMCallKitProxy (Helpers) |
||||
|
||||
+ (CXCallUpdate *)makeCXUpdateWithHandle:(nullable NSString *)handle displayName:(nullable NSString *)displayName hasVideo:(BOOL)hasVideo { |
||||
CXCallUpdate *update = [[CXCallUpdate alloc] init]; |
||||
update.supportsDTMF = false; |
||||
update.supportsHolding = false; |
||||
update.supportsGrouping = false; |
||||
update.supportsUngrouping = false; |
||||
update.hasVideo = hasVideo; |
||||
update.localizedCallerName = displayName; |
||||
|
||||
if (handle) { |
||||
update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:handle]; |
||||
} |
||||
|
||||
return update; |
||||
} |
||||
|
||||
@end |
@ -1,231 +0,0 @@ |
||||
/* |
||||
* Copyright @ 2018-present 8x8, Inc. |
||||
* |
||||
* 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 |
||||
|
||||
public protocol CXProviderProtocol: AnyObject { |
||||
var configuration: CXProviderConfiguration { get set } |
||||
func setDelegate(_ delegate: CXProviderDelegate?, queue: DispatchQueue?) |
||||
func reportNewIncomingCall(with UUID: UUID, update: CXCallUpdate, completion: @escaping (Error?) -> Void) |
||||
func reportCall(with UUID: UUID, updated update: CXCallUpdate) |
||||
func reportCall(with UUID: UUID, endedAt dateEnded: Date?, reason endedReason: CXCallEndedReason) |
||||
func reportOutgoingCall(with UUID: UUID, startedConnectingAt dateStartedConnecting: Date?) |
||||
func reportOutgoingCall(with UUID: UUID, connectedAt dateConnected: Date?) |
||||
func invalidate() |
||||
} |
||||
|
||||
public protocol CXCallControllerProtocol: AnyObject { |
||||
var calls: [CXCall] { get } |
||||
func request(_ transaction: CXTransaction, completion: @escaping (Error?) -> Swift.Void) |
||||
} |
||||
|
||||
extension CXProvider: CXProviderProtocol {} |
||||
extension CXCallController: CXCallControllerProtocol { |
||||
public var calls: [CXCall] { |
||||
return callObserver.calls |
||||
} |
||||
} |
||||
|
||||
/// JitsiMeet CallKit proxy |
||||
// NOTE: The methods this class exposes are meant to be called in the UI thread. |
||||
// All delegate methods called by JMCallKitEmitter will be called in the UI thread. |
||||
@objc public final class JMCallKitProxy: NSObject { |
||||
|
||||
private override init() {} |
||||
|
||||
// MARK: - CallKit proxy |
||||
|
||||
public static var callKitProvider: CXProviderProtocol? |
||||
public static var callKitCallController: CXCallControllerProtocol? |
||||
|
||||
private static var defaultProvider: CXProvider? |
||||
|
||||
private static var provider: CXProviderProtocol? { |
||||
callKitProvider ?? defaultProvider |
||||
} |
||||
|
||||
private static var callController: CXCallControllerProtocol { |
||||
callKitCallController ?? defaultCallController |
||||
} |
||||
|
||||
private static var providerConfiguration: CXProviderConfiguration? { |
||||
didSet { |
||||
guard let configuration = providerConfiguration else { return } |
||||
provider?.configuration = configuration |
||||
provider?.setDelegate(emitter, queue: nil) |
||||
} |
||||
} |
||||
|
||||
private static let defaultCallController: CXCallController = { |
||||
return CXCallController() |
||||
}() |
||||
|
||||
private static let emitter: JMCallKitEmitter = { |
||||
return JMCallKitEmitter() |
||||
}() |
||||
|
||||
/// Enables the proxy in between CallKit and the consumers of the SDK. |
||||
/// Defaults to disabled. Set to true when you want to use CallKit. |
||||
@objc public static var enabled: Bool = false { |
||||
didSet { |
||||
if callKitProvider == nil { |
||||
provider?.invalidate() |
||||
} |
||||
|
||||
if enabled { |
||||
let configuration = providerConfiguration ?? CXProviderConfiguration(localizedName: "") |
||||
if callKitProvider == nil { |
||||
defaultProvider = CXProvider(configuration: configuration) |
||||
} |
||||
|
||||
provider?.setDelegate(emitter, queue: nil) |
||||
} else { |
||||
provider?.setDelegate(nil, queue: nil) |
||||
} |
||||
} |
||||
} |
||||
|
||||
@objc public static func configureProvider(localizedName: String, |
||||
ringtoneSound: String?, |
||||
iconTemplateImageData: Data?) { |
||||
guard enabled else { return } |
||||
|
||||
let configuration = CXProviderConfiguration(localizedName: localizedName) |
||||
configuration.iconTemplateImageData = iconTemplateImageData |
||||
configuration.maximumCallGroups = 1 |
||||
configuration.maximumCallsPerCallGroup = 1 |
||||
configuration.ringtoneSound = ringtoneSound |
||||
configuration.supportedHandleTypes = [CXHandle.HandleType.generic] |
||||
configuration.supportsVideo = true |
||||
|
||||
providerConfiguration = configuration |
||||
} |
||||
|
||||
@objc public static func isProviderConfigured() -> Bool { |
||||
return providerConfiguration != nil |
||||
} |
||||
|
||||
@objc public static func addListener(_ listener: JMCallKitListener) { |
||||
emitter.addListener(listener) |
||||
} |
||||
|
||||
@objc public static func removeListener(_ listener: JMCallKitListener) { |
||||
emitter.removeListener(listener) |
||||
} |
||||
|
||||
@objc public static func hasActiveCallForUUID(_ callUUID: String) -> Bool { |
||||
let activeCallForUUID = callController.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) |
||||
provider?.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) |
||||
provider?.reportCall(with: UUID, updated: callUpdate) |
||||
} |
||||
|
||||
@objc public static func reportCall( |
||||
with UUID: UUID, |
||||
endedAt dateEnded: Date?, |
||||
reason endedReason: CXCallEndedReason) { |
||||
guard enabled else { return } |
||||
provider?.reportCall(with: UUID, |
||||
endedAt: dateEnded, |
||||
reason: endedReason) |
||||
} |
||||
|
||||
@objc public static func reportOutgoingCall( |
||||
with UUID: UUID, |
||||
startedConnectingAt dateStartedConnecting: Date?) { |
||||
guard enabled else { return } |
||||
provider?.reportOutgoingCall(with: UUID, |
||||
startedConnectingAt: dateStartedConnecting) |
||||
} |
||||
|
||||
@objc public static func reportOutgoingCall( |
||||
with UUID: UUID, |
||||
connectedAt dateConnected: Date?) { |
||||
guard enabled else { return } |
||||
|
||||
provider?.reportOutgoingCall(with: UUID, connectedAt: dateConnected) |
||||
} |
||||
|
||||
@objc public static func request( |
||||
_ transaction: CXTransaction, |
||||
completion: @escaping (Error?) -> Swift.Void) { |
||||
guard enabled else { return } |
||||
|
||||
// XXX keep track of muted actions to avoid "ping-pong"ing. See |
||||
// JMCallKitEmitter for details on the CXSetMutedCallAction handling. |
||||
for action in transaction.actions { |
||||
if (action as? CXSetMutedCallAction) != nil { |
||||
emitter.addMuteAction(action.uuid) |
||||
} |
||||
} |
||||
|
||||
callController.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 |
||||
} |
||||
} |
||||
|
Loading…
Reference in new issue