From e68ede65e1ba5bc5c4d752924eefc09e337d3e41 Mon Sep 17 00:00:00 2001 From: Alex Bumbu Date: Wed, 14 Sep 2022 19:52:39 +0300 Subject: [PATCH] feat(iOS): callkit objc implementation --- ios/sdk/sdk.xcodeproj/project.pbxproj | 58 ++-- ios/sdk/src/JitsiMeetSDK-Swift.h | 271 ------------------- ios/sdk/src/JitsiMeetSDK.h | 2 + ios/sdk/src/callkit/CallKit.m | 2 +- ios/sdk/src/callkit/JMCallKitEmitter.h | 35 +++ ios/sdk/src/callkit/JMCallKitEmitter.m | 116 ++++++++ ios/sdk/src/callkit/JMCallKitEmitter.swift | 118 -------- ios/sdk/src/callkit/JMCallKitListener.h | 34 +++ ios/sdk/src/callkit/JMCallKitListener.swift | 38 --- ios/sdk/src/callkit/JMCallKitProxy.h | 87 ++++++ ios/sdk/src/callkit/JMCallKitProxy.m | 284 ++++++++++++++++++++ ios/sdk/src/callkit/JMCallKitProxy.swift | 231 ---------------- 12 files changed, 591 insertions(+), 685 deletions(-) delete mode 100644 ios/sdk/src/JitsiMeetSDK-Swift.h create mode 100644 ios/sdk/src/callkit/JMCallKitEmitter.h create mode 100644 ios/sdk/src/callkit/JMCallKitEmitter.m delete mode 100644 ios/sdk/src/callkit/JMCallKitEmitter.swift create mode 100644 ios/sdk/src/callkit/JMCallKitListener.h delete mode 100644 ios/sdk/src/callkit/JMCallKitListener.swift create mode 100644 ios/sdk/src/callkit/JMCallKitProxy.h create mode 100644 ios/sdk/src/callkit/JMCallKitProxy.m delete mode 100644 ios/sdk/src/callkit/JMCallKitProxy.swift diff --git a/ios/sdk/sdk.xcodeproj/project.pbxproj b/ios/sdk/sdk.xcodeproj/project.pbxproj index 0e73e4911..1172bcd72 100644 --- a/ios/sdk/sdk.xcodeproj/project.pbxproj +++ b/ios/sdk/sdk.xcodeproj/project.pbxproj @@ -23,6 +23,16 @@ 0BCA49611EC4B6C600B793EE /* Proximity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BCA495E1EC4B6C600B793EE /* Proximity.m */; }; 0BD906EA1EC0C00300C8C18E /* JitsiMeet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BD906E81EC0C00300C8C18E /* JitsiMeet.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3453F4A32680898C4A40E821 /* libPods-JitsiMeetSDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 927ED7DF018DE5E12C4C3404 /* libPods-JitsiMeetSDK.a */; }; + 4E0EF63028CA2FB3005D1B03 /* JMCallKitEmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E0EF62E28CA2FB3005D1B03 /* JMCallKitEmitter.h */; }; + 4E0EF63128CA2FB3005D1B03 /* JMCallKitEmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E0EF62E28CA2FB3005D1B03 /* JMCallKitEmitter.h */; }; + 4E0EF63228CA2FB3005D1B03 /* JMCallKitEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E0EF62F28CA2FB3005D1B03 /* JMCallKitEmitter.m */; }; + 4E0EF63328CA2FB3005D1B03 /* JMCallKitEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E0EF62F28CA2FB3005D1B03 /* JMCallKitEmitter.m */; }; + 4E0EF63528CA317E005D1B03 /* JMCallKitListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E0EF63428CA317E005D1B03 /* JMCallKitListener.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4E0EF63628CA317E005D1B03 /* JMCallKitListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E0EF63428CA317E005D1B03 /* JMCallKitListener.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4E0EF63928CA4069005D1B03 /* JMCallKitProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E0EF63728CA4069005D1B03 /* JMCallKitProxy.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4E0EF63A28CA4069005D1B03 /* JMCallKitProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E0EF63728CA4069005D1B03 /* JMCallKitProxy.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4E0EF63B28CA4069005D1B03 /* JMCallKitProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E0EF63828CA4069005D1B03 /* JMCallKitProxy.m */; }; + 4E0EF63C28CA4069005D1B03 /* JMCallKitProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E0EF63828CA4069005D1B03 /* JMCallKitProxy.m */; }; 4E51B76425E5345E0038575A /* ScheenshareEventEmiter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E51B76225E5345E0038575A /* ScheenshareEventEmiter.h */; }; 4E51B76525E5345E0038575A /* ScheenshareEventEmiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */; }; 4EBA6E61286072E300B31882 /* JitsiMeetViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EBA6E5F286072E300B31882 /* JitsiMeetViewController.h */; }; @@ -33,14 +43,11 @@ 4ED4FFF42721B9B90074E620 /* JitsiAudioSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ED4FFF22721B9B90074E620 /* JitsiAudioSession.m */; }; 4EEC9630286C73A2008705FA /* JitsiMeetView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EEC962E286C73A2008705FA /* JitsiMeetView+Private.h */; }; 4EEC9631286C73A2008705FA /* JitsiMeetView+Private.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EEC962F286C73A2008705FA /* JitsiMeetView+Private.m */; }; - 6F08DF7D4458EE3CF3F36F6D /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; + 6F08DF7D4458EE3CF3F36F6D /* (null) in Frameworks */ = {isa = PBXBuildFile; }; 9A8EE79C77C17743BB66E8BD /* libPods-JitsiMeetSDKLite.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B46497DE9A95BDF5E312AF48 /* libPods-JitsiMeetSDKLite.a */; }; A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */ = {isa = PBXBuildFile; fileRef = A4A934E8212F3ADB001E9388 /* Dropbox.m */; }; 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 */; }; - C69EFA0C209A0F660027712B /* JMCallKitEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA09209A0F650027712B /* JMCallKitEmitter.swift */; }; - C69EFA0D209A0F660027712B /* JMCallKitProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0A209A0F660027712B /* JMCallKitProxy.swift */; }; - C69EFA0E209A0F660027712B /* JMCallKitListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0B209A0F660027712B /* JMCallKitListener.swift */; }; C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425E204EF76800E062DD /* DragGestureController.swift */; }; C6CC49AF207412CF000DFA42 /* PiPViewCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */; }; C81E9AB925AC5AD800B134D9 /* ExternalAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = C81E9AB825AC5AD800B134D9 /* ExternalAPI.h */; }; @@ -49,8 +56,6 @@ DE438CDA2350934700DD541D /* JavaScriptSandbox.m in Sources */ = {isa = PBXBuildFile; fileRef = DE438CD82350934700DD541D /* JavaScriptSandbox.m */; }; DE65AACA2317FFCD00290BEC /* LogUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DE65AAC92317FFCD00290BEC /* LogUtils.h */; }; DE65AACC2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */; }; - DE66914428BCC1C7007C4533 /* JitsiMeetSDK-Swift.h in Headers */ = {isa = PBXBuildFile; fileRef = DE66914328BCC1C7007C4533 /* JitsiMeetSDK-Swift.h */; }; - DE66914528BCC1C7007C4533 /* JitsiMeetSDK-Swift.h in Headers */ = {isa = PBXBuildFile; fileRef = DE66914328BCC1C7007C4533 /* JitsiMeetSDK-Swift.h */; }; DE762DB422AFDE76000DEBD6 /* JitsiMeetUserInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DE762DB322AFDE76000DEBD6 /* JitsiMeetUserInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; DE762DB622AFDE8D000DEBD6 /* JitsiMeetUserInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DE762DB522AFDE8D000DEBD6 /* JitsiMeetUserInfo.m */; }; DE81A2D42316AC4D00AE1940 /* JitsiMeetLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = DE81A2D22316AC4D00AE1940 /* JitsiMeetLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -93,15 +98,12 @@ DE9A0151289A9A9A00E41CBB /* LocaleDetector.m in Sources */ = {isa = PBXBuildFile; fileRef = DEFC743D21B178FA00E4DD96 /* LocaleDetector.m */; }; DE9A0152289A9A9A00E41CBB /* AudioMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BCA495C1EC4B6C600B793EE /* AudioMode.m */; }; DE9A0153289A9A9A00E41CBB /* Proximity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0BCA495E1EC4B6C600B793EE /* Proximity.m */; }; - DE9A0154289A9A9A00E41CBB /* JMCallKitEmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA09209A0F650027712B /* JMCallKitEmitter.swift */; }; DE9A0155289A9A9A00E41CBB /* ReactUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DEFE535521FB2E8300011A3A /* ReactUtils.m */; }; DE9A0156289A9A9A00E41CBB /* JitsiMeetView+Private.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EEC962F286C73A2008705FA /* JitsiMeetView+Private.m */; }; DE9A0157289A9A9A00E41CBB /* DragGestureController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A3425E204EF76800E062DD /* DragGestureController.swift */; }; DE9A0158289A9A9A00E41CBB /* ScheenshareEventEmiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */; }; DE9A015A289A9A9A00E41CBB /* JitsiMeetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EBA6E60286072E300B31882 /* JitsiMeetViewController.m */; }; - DE9A015B289A9A9A00E41CBB /* JMCallKitProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0A209A0F660027712B /* JMCallKitProxy.swift */; }; DE9A015C289A9A9A00E41CBB /* JitsiMeetLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = DE81A2D32316AC4D00AE1940 /* JitsiMeetLogger.m */; }; - DE9A015D289A9A9A00E41CBB /* JMCallKitListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = C69EFA0B209A0F660027712B /* JMCallKitListener.swift */; }; DE9A015E289A9A9A00E41CBB /* JitsiMeetView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B412F171EDEC65D00B1A0A6 /* JitsiMeetView.m */; }; DE9A015F289A9A9A00E41CBB /* JitsiMeet.m in Sources */ = {isa = PBXBuildFile; fileRef = DEFE535321FB1BF800011A3A /* JitsiMeet.m */; }; DE9A0160289A9A9A00E41CBB /* JavaScriptSandbox.m in Sources */ = {isa = PBXBuildFile; fileRef = DE438CD82350934700DD541D /* JavaScriptSandbox.m */; }; @@ -139,6 +141,11 @@ 0BD906E51EC0C00300C8C18E /* JitsiMeetSDK.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JitsiMeetSDK.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 0BD906E81EC0C00300C8C18E /* JitsiMeet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeet.h; sourceTree = ""; }; 0BD906E91EC0C00300C8C18E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 4E0EF62E28CA2FB3005D1B03 /* JMCallKitEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMCallKitEmitter.h; sourceTree = ""; }; + 4E0EF62F28CA2FB3005D1B03 /* JMCallKitEmitter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMCallKitEmitter.m; sourceTree = ""; }; + 4E0EF63428CA317E005D1B03 /* JMCallKitListener.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMCallKitListener.h; sourceTree = ""; }; + 4E0EF63728CA4069005D1B03 /* JMCallKitProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JMCallKitProxy.h; sourceTree = ""; }; + 4E0EF63828CA4069005D1B03 /* JMCallKitProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JMCallKitProxy.m; sourceTree = ""; }; 4E51B76225E5345E0038575A /* ScheenshareEventEmiter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScheenshareEventEmiter.h; sourceTree = ""; }; 4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ScheenshareEventEmiter.m; sourceTree = ""; }; 4EBA6E5F286072E300B31882 /* JitsiMeetViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeetViewController.h; sourceTree = ""; }; @@ -161,9 +168,6 @@ B46497DE9A95BDF5E312AF48 /* libPods-JitsiMeetSDKLite.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JitsiMeetSDKLite.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 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 = ""; }; 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 = ""; }; - C69EFA09209A0F650027712B /* JMCallKitEmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JMCallKitEmitter.swift; sourceTree = ""; }; - C69EFA0A209A0F660027712B /* JMCallKitProxy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JMCallKitProxy.swift; sourceTree = ""; }; - C69EFA0B209A0F660027712B /* JMCallKitListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JMCallKitListener.swift; sourceTree = ""; }; C6A3425E204EF76800E062DD /* DragGestureController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragGestureController.swift; sourceTree = ""; }; C6CC49AE207412CF000DFA42 /* PiPViewCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PiPViewCoordinator.swift; sourceTree = ""; }; C81E9AB825AC5AD800B134D9 /* ExternalAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExternalAPI.h; sourceTree = ""; }; @@ -172,7 +176,6 @@ DE438CD82350934700DD541D /* JavaScriptSandbox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JavaScriptSandbox.m; sourceTree = ""; }; DE65AAC92317FFCD00290BEC /* LogUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogUtils.h; sourceTree = ""; }; DE65AACB2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetBaseLogHandler+Private.h"; sourceTree = ""; }; - DE66914328BCC1C7007C4533 /* JitsiMeetSDK-Swift.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetSDK-Swift.h"; sourceTree = ""; }; DE762DB322AFDE76000DEBD6 /* JitsiMeetUserInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JitsiMeetUserInfo.h; sourceTree = ""; }; DE762DB522AFDE8D000DEBD6 /* JitsiMeetUserInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JitsiMeetUserInfo.m; sourceTree = ""; }; DE762DB722AFE166000DEBD6 /* JitsiMeetUserInfo+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JitsiMeetUserInfo+Private.h"; sourceTree = ""; }; @@ -203,7 +206,7 @@ files = ( 0BB9AD791F5EC6D7001C08DB /* Intents.framework in Frameworks */, 0BB9AD771F5EC6CE001C08DB /* CallKit.framework in Frameworks */, - 6F08DF7D4458EE3CF3F36F6D /* BuildFile in Frameworks */, + 6F08DF7D4458EE3CF3F36F6D /* (null) in Frameworks */, 3453F4A32680898C4A40E821 /* libPods-JitsiMeetSDK.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -306,7 +309,6 @@ 4E51B76225E5345E0038575A /* ScheenshareEventEmiter.h */, 4E51B76325E5345E0038575A /* ScheenshareEventEmiter.m */, DE9A0170289A9A9A00E41CBB /* Lite-Info.plist */, - DE66914328BCC1C7007C4533 /* JitsiMeetSDK-Swift.h */, ); path = src; sourceTree = ""; @@ -349,9 +351,11 @@ isa = PBXGroup; children = ( 0BB9AD7A1F5EC8F4001C08DB /* CallKit.m */, - C69EFA09209A0F650027712B /* JMCallKitEmitter.swift */, - C69EFA0B209A0F660027712B /* JMCallKitListener.swift */, - C69EFA0A209A0F660027712B /* JMCallKitProxy.swift */, + 4E0EF62E28CA2FB3005D1B03 /* JMCallKitEmitter.h */, + 4E0EF62F28CA2FB3005D1B03 /* JMCallKitEmitter.m */, + 4E0EF63428CA317E005D1B03 /* JMCallKitListener.h */, + 4E0EF63728CA4069005D1B03 /* JMCallKitProxy.h */, + 4E0EF63828CA4069005D1B03 /* JMCallKitProxy.m */, ); path = callkit; sourceTree = ""; @@ -379,10 +383,12 @@ DEA9F284258A5D9900D4CD74 /* JitsiMeetSDK.h in Headers */, 4E51B76425E5345E0038575A /* ScheenshareEventEmiter.h in Headers */, DE65AACC2318028300290BEC /* JitsiMeetBaseLogHandler+Private.h in Headers */, - DE66914428BCC1C7007C4533 /* JitsiMeetSDK-Swift.h in Headers */, 4EBA6E652860B1E800B31882 /* JitsiMeetRenderingView.h in Headers */, 0B412F221EDEF6EA00B1A0A6 /* JitsiMeetViewDelegate.h in Headers */, + 4E0EF63528CA317E005D1B03 /* JMCallKitListener.h in Headers */, + 4E0EF63028CA2FB3005D1B03 /* JMCallKitEmitter.h in Headers */, 4ED4FFF32721B9B90074E620 /* JitsiAudioSession.h in Headers */, + 4E0EF63928CA4069005D1B03 /* JMCallKitProxy.h in Headers */, 4EEC9630286C73A2008705FA /* JitsiMeetView+Private.h in Headers */, 0BD906EA1EC0C00300C8C18E /* JitsiMeet.h in Headers */, DE81A2D42316AC4D00AE1940 /* JitsiMeetLogger.h in Headers */, @@ -405,10 +411,12 @@ DE9A0134289A9A9A00E41CBB /* JitsiMeetSDK.h in Headers */, DE9A0135289A9A9A00E41CBB /* ScheenshareEventEmiter.h in Headers */, DE9A0136289A9A9A00E41CBB /* JitsiMeetBaseLogHandler+Private.h in Headers */, - DE66914528BCC1C7007C4533 /* JitsiMeetSDK-Swift.h in Headers */, DE9A0137289A9A9A00E41CBB /* JitsiMeetRenderingView.h in Headers */, DE9A0138289A9A9A00E41CBB /* JitsiMeetViewDelegate.h in Headers */, + 4E0EF63628CA317E005D1B03 /* JMCallKitListener.h in Headers */, + 4E0EF63128CA2FB3005D1B03 /* JMCallKitEmitter.h in Headers */, DE9A0139289A9A9A00E41CBB /* JitsiAudioSession.h in Headers */, + 4E0EF63A28CA4069005D1B03 /* JMCallKitProxy.h in Headers */, DE9A013A289A9A9A00E41CBB /* JitsiMeetView+Private.h in Headers */, DE9A013B289A9A9A00E41CBB /* JitsiMeet.h in Headers */, DE9A013C289A9A9A00E41CBB /* JitsiMeetLogger.h in Headers */, @@ -677,6 +685,7 @@ files = ( 0BB9AD7B1F5EC8F4001C08DB /* CallKit.m in Sources */, DE81A2DF2317ED5400AE1940 /* JitsiMeetBaseLogHandler.m in Sources */, + 4E0EF63B28CA4069005D1B03 /* JMCallKitProxy.m in Sources */, 4EBA6E662860B1E800B31882 /* JitsiMeetRenderingView.m in Sources */, 4ED4FFF42721B9B90074E620 /* JitsiAudioSession.m in Sources */, 0BB9AD7D1F60356D001C08DB /* AppInfo.m in Sources */, @@ -692,16 +701,14 @@ DEFC743F21B178FA00E4DD96 /* LocaleDetector.m in Sources */, 0BCA495F1EC4B6C600B793EE /* AudioMode.m in Sources */, 0BCA49611EC4B6C600B793EE /* Proximity.m in Sources */, - C69EFA0C209A0F660027712B /* JMCallKitEmitter.swift in Sources */, + 4E0EF63228CA2FB3005D1B03 /* JMCallKitEmitter.m in Sources */, DEFE535621FB2E8300011A3A /* ReactUtils.m in Sources */, 4EEC9631286C73A2008705FA /* JitsiMeetView+Private.m in Sources */, C6A34261204EF76800E062DD /* DragGestureController.swift in Sources */, 4E51B76525E5345E0038575A /* ScheenshareEventEmiter.m in Sources */, A4A934E9212F3ADB001E9388 /* Dropbox.m in Sources */, 4EBA6E62286072E300B31882 /* JitsiMeetViewController.m in Sources */, - C69EFA0D209A0F660027712B /* JMCallKitProxy.swift in Sources */, DE81A2D52316AC4D00AE1940 /* JitsiMeetLogger.m in Sources */, - C69EFA0E209A0F660027712B /* JMCallKitListener.swift in Sources */, 0B412F191EDEC65D00B1A0A6 /* JitsiMeetView.m in Sources */, DEFE535421FB1BF800011A3A /* JitsiMeet.m in Sources */, DE438CDA2350934700DD541D /* JavaScriptSandbox.m in Sources */, @@ -716,6 +723,7 @@ DE9A0144289A9A9A00E41CBB /* JitsiMeetBaseLogHandler.m in Sources */, DE9A0145289A9A9A00E41CBB /* JitsiMeetRenderingView.m in Sources */, DE9A0146289A9A9A00E41CBB /* JitsiAudioSession.m in Sources */, + 4E0EF63C28CA4069005D1B03 /* JMCallKitProxy.m in Sources */, DE9A0147289A9A9A00E41CBB /* AppInfo.m in Sources */, DE9A0148289A9A9A00E41CBB /* LogBridge.m in Sources */, DE9A0149289A9A9A00E41CBB /* RNRootView.m in Sources */, @@ -729,15 +737,13 @@ DE9A0151289A9A9A00E41CBB /* LocaleDetector.m in Sources */, DE9A0152289A9A9A00E41CBB /* AudioMode.m in Sources */, DE9A0153289A9A9A00E41CBB /* Proximity.m in Sources */, - DE9A0154289A9A9A00E41CBB /* JMCallKitEmitter.swift in Sources */, DE9A0155289A9A9A00E41CBB /* ReactUtils.m in Sources */, DE9A0156289A9A9A00E41CBB /* JitsiMeetView+Private.m in Sources */, DE9A0157289A9A9A00E41CBB /* DragGestureController.swift in Sources */, DE9A0158289A9A9A00E41CBB /* ScheenshareEventEmiter.m in Sources */, DE9A015A289A9A9A00E41CBB /* JitsiMeetViewController.m in Sources */, - DE9A015B289A9A9A00E41CBB /* JMCallKitProxy.swift in Sources */, DE9A015C289A9A9A00E41CBB /* JitsiMeetLogger.m in Sources */, - DE9A015D289A9A9A00E41CBB /* JMCallKitListener.swift in Sources */, + 4E0EF63328CA2FB3005D1B03 /* JMCallKitEmitter.m in Sources */, DE9A015E289A9A9A00E41CBB /* JitsiMeetView.m in Sources */, DE9A015F289A9A9A00E41CBB /* JitsiMeet.m in Sources */, DE9A0160289A9A9A00E41CBB /* JavaScriptSandbox.m in Sources */, diff --git a/ios/sdk/src/JitsiMeetSDK-Swift.h b/ios/sdk/src/JitsiMeetSDK-Swift.h deleted file mode 100644 index 11e96f43d..000000000 --- a/ios/sdk/src/JitsiMeetSDK-Swift.h +++ /dev/null @@ -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() -# include -#endif - -#pragma clang diagnostic ignored "-Wauto-import" -#include -#include -#include -#include - -#if !defined(SWIFT_TYPEDEFS) -# define SWIFT_TYPEDEFS 1 -# if __has_include() -# include -# 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 -@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 _Nonnull)listener; -+ (void)removeListener:(id _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 diff --git a/ios/sdk/src/JitsiMeetSDK.h b/ios/sdk/src/JitsiMeetSDK.h index d9a5d2368..22835327a 100644 --- a/ios/sdk/src/JitsiMeetSDK.h +++ b/ios/sdk/src/JitsiMeetSDK.h @@ -22,3 +22,5 @@ #import #import #import +#import +#import diff --git a/ios/sdk/src/callkit/CallKit.m b/ios/sdk/src/callkit/CallKit.m index 7fce1a907..9fa88f00b 100644 --- a/ios/sdk/src/callkit/CallKit.m +++ b/ios/sdk/src/callkit/CallKit.m @@ -30,7 +30,7 @@ #import #import "../JitsiAudioSession.h" -#import "../JitsiMeetSDK-Swift.h" +#import "JMCallKitProxy.h" // The events emitted/supported by RNCallKit: diff --git a/ios/sdk/src/callkit/JMCallKitEmitter.h b/ios/sdk/src/callkit/JMCallKitEmitter.h new file mode 100644 index 000000000..fdd908ed2 --- /dev/null +++ b/ios/sdk/src/callkit/JMCallKitEmitter.h @@ -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 +#import +#import "JMCallKitListener.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface JMCallKitEmitter : NSObject + +#pragma mark Add/Remove listeners +- (void)addListener:(id)listener; +- (void)removeListener:(id)listener; + +#pragma mark Add mute action +- (void)addMuteAction:(NSUUID *)actionUUID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/sdk/src/callkit/JMCallKitEmitter.m b/ios/sdk/src/callkit/JMCallKitEmitter.m new file mode 100644 index 000000000..cafcb15ac --- /dev/null +++ b/ios/sdk/src/callkit/JMCallKitEmitter.m @@ -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> *listeners; +@property(nonatomic, strong) NSMutableSet *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)listener { + if (![self.listeners containsObject:listener]) { + [self.listeners addObject:listener]; + } +} + +- (void)removeListener:(id)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 diff --git a/ios/sdk/src/callkit/JMCallKitEmitter.swift b/ios/sdk/src/callkit/JMCallKitEmitter.swift deleted file mode 100644 index 3d861584a..000000000 --- a/ios/sdk/src/callkit/JMCallKitEmitter.swift +++ /dev/null @@ -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() - - 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) - } - } -} diff --git a/ios/sdk/src/callkit/JMCallKitListener.h b/ios/sdk/src/callkit/JMCallKitListener.h new file mode 100644 index 000000000..fcc59163e --- /dev/null +++ b/ios/sdk/src/callkit/JMCallKitListener.h @@ -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 +#import +#import + +@protocol JMCallKitListener + +@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 diff --git a/ios/sdk/src/callkit/JMCallKitListener.swift b/ios/sdk/src/callkit/JMCallKitListener.swift deleted file mode 100644 index 02aeedfc4..000000000 --- a/ios/sdk/src/callkit/JMCallKitListener.swift +++ /dev/null @@ -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) -} diff --git a/ios/sdk/src/callkit/JMCallKitProxy.h b/ios/sdk/src/callkit/JMCallKitProxy.h new file mode 100644 index 000000000..82cd72c1a --- /dev/null +++ b/ios/sdk/src/callkit/JMCallKitProxy.h @@ -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 +#import +#import "JMCallKitListener.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol CXProviderProtocol + +@property (nonatomic, readwrite, copy) CXProviderConfiguration* configuration; + +- (void)setDelegate:(nullable id)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 + +@property (nonatomic, readonly) NSArray *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 callKitProvider; +@property (class) id 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)listener NS_SWIFT_NAME(addListener(_:)); ++ (void)removeListener:(nonnull id)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 diff --git a/ios/sdk/src/callkit/JMCallKitProxy.m b/ios/sdk/src/callkit/JMCallKitProxy.m new file mode 100644 index 000000000..899d152a2 --- /dev/null +++ b/ios/sdk/src/callkit/JMCallKitProxy.m @@ -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) +@end + +@implementation CXProvider(CXProviderProtocol) +@end + +#pragma mark - +@interface CXCallController(CXCallControllerProtocol) + +@property (nonatomic, readonly) NSArray *calls; + +@end + +@implementation CXCallController(CXCallControllerProtocol) + +@dynamic calls; + +- (NSArray *)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 _callKitProvider = nil; +static id _callKitCallController = nil; +static BOOL _enabled = false; +static CXProvider *_defaultProvider = nil; +static CXProviderConfiguration *_providerConfiguration = nil; + +#pragma mark CallJit proxy + ++ (id)callKitProvider { + return _callKitProvider; +} + ++ (void)setCallKitProvider:(id)callKitProvider { + if (_callKitProvider != callKitProvider) { + _callKitProvider = callKitProvider; + } +} + ++ (id)callKitCallController { + return _callKitCallController; +} + ++ (void)setCallKitCallController:(id)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)provider { + return self.callKitProvider != nil ? self.callKitProvider : self.defaultProvider; +} + ++ (id)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)listener { + [self.emitter addListener:listener]; +} + ++ (void)removeListener:(nonnull id)listener { + [self.emitter removeListener:listener]; +} + ++ (BOOL)hasActiveCallForUUID:(nonnull NSString *)callUUID { + CXCall *activeCallForUUID = [[self.callController calls] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(CXCall *evaluatedObject, NSDictionary *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 diff --git a/ios/sdk/src/callkit/JMCallKitProxy.swift b/ios/sdk/src/callkit/JMCallKitProxy.swift deleted file mode 100644 index c83d1aa0c..000000000 --- a/ios/sdk/src/callkit/JMCallKitProxy.swift +++ /dev/null @@ -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 - } -} -