Add CallKit basic integration for outgoing/incoming calls

This commit is contained in:
QuentinArguillere
2020-08-06 13:58:26 +02:00
parent 4830d38167
commit f723655265
5 changed files with 156 additions and 14 deletions

View File

@@ -14,6 +14,7 @@
6604166024D451F40064FC6C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6604165F24D451F40064FC6C /* Preview Assets.xcassets */; };
6604166324D451F40064FC6C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6604166124D451F40064FC6C /* LaunchScreen.storyboard */; };
6604166B24D453240064FC6C /* CallExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6604166A24D453240064FC6C /* CallExample.swift */; };
66B14FBB24DAF68E0041952F /* CallKitProviderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66B14FBA24DAF68E0041952F /* CallKitProviderDelegate.swift */; };
E1569C6E0564D0FD3FF9B4AF /* Pods_CallTutorial.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DC1D5CBF786F45B5E0D811F /* Pods_CallTutorial.framework */; };
/* End PBXBuildFile section */
@@ -28,6 +29,7 @@
6604166224D451F40064FC6C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
6604166424D451F40064FC6C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
6604166A24D453240064FC6C /* CallExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallExample.swift; sourceTree = "<group>"; };
66B14FBA24DAF68E0041952F /* CallKitProviderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallKitProviderDelegate.swift; sourceTree = "<group>"; };
79CE65CD0070AF94E21BFCE7 /* Pods-CallTutorial.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CallTutorial.debug.xcconfig"; path = "Target Support Files/Pods-CallTutorial/Pods-CallTutorial.debug.xcconfig"; sourceTree = "<group>"; };
C26219FCE26251F1C3C2E96E /* Pods-CallTutorial.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CallTutorial.release.xcconfig"; path = "Target Support Files/Pods-CallTutorial/Pods-CallTutorial.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -84,6 +86,7 @@
children = (
6604165624D451F10064FC6C /* AppDelegate.swift */,
6604165824D451F10064FC6C /* SceneDelegate.swift */,
66B14FBA24DAF68E0041952F /* CallKitProviderDelegate.swift */,
6604166A24D453240064FC6C /* CallExample.swift */,
6604165A24D451F10064FC6C /* ContentView.swift */,
6604165C24D451F40064FC6C /* Assets.xcassets */,
@@ -221,6 +224,7 @@
6604165724D451F10064FC6C /* AppDelegate.swift in Sources */,
6604165924D451F10064FC6C /* SceneDelegate.swift in Sources */,
6604165B24D451F10064FC6C /* ContentView.swift in Sources */,
66B14FBB24DAF68E0041952F /* CallKitProviderDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -37,6 +37,9 @@ class CallExampleContext : ObservableObject
@Published var passwd : String = "peche5"
@Published var loggedIn: Bool = false
var providerDelegate : CallKitProviderDelegate!
@Published var enableCallKit = false;
init()
{
mCallStateTracer.tutorialContext = self
@@ -56,17 +59,19 @@ class CallExampleContext : ObservableObject
// main loop for receiving notifications and doing background linphonecore work:
mCore.autoIterateEnabled = true
mCore.callkitEnabled = true
try? mCore.start()
mVideoDevices = mCore.videoDevicesList
mCore.addDelegate(delegate: mCallStateTracer)
mCore.addDelegate(delegate: mRegistrationDelegate)
providerDelegate = CallKitProviderDelegate(context : self)
}
func registrationExample()
{
let factory = Factory.Instance
do {
let proxy_cfg = try mCore.createProxyConfig()
@@ -120,20 +125,24 @@ class CallExampleContext : ObservableObject
}
// Initiate a call
func outgoingCallKitCallExample()
{
providerDelegate.outgoingCall(uuid: UUID())
}
// Terminate a call
func stopCall()
{
if (callRunning)
if ((callRunning || isCallIncoming) && mCall.state != Call.State.End)
{
if (mCall.state != Call.State.End){
// terminate the call
print("Terminating the call...\n")
do {
try mCall.terminate()
} catch {
print(error)
}
}
// terminate the call
print("Terminating the call...\n")
do {
try mCall.terminate()
} catch {
print(error)
}
}
}
@@ -211,10 +220,15 @@ class CallStateDelegate: CoreDelegate {
if (cstate == .IncomingReceived) {
tutorialContext.mCall = call
tutorialContext.isCallIncoming = true
if (tutorialContext.enableCallKit)
{
tutorialContext.providerDelegate.reportIncomingCall(call: call, uuid: UUID(), handle: "Incoming Test Call", hasVideo: false)
}
} else if (cstate == .OutgoingRinging) {
tutorialContext.callRunning = true
} else if (cstate == .End) {
tutorialContext.callRunning = false
tutorialContext.isCallIncoming = false;
}
}
}

View File

@@ -0,0 +1,107 @@
//
// ProviderDelegate.swift
// CallTutorial
//
// Created by QuentinArguillere on 05/08/2020.
// Copyright © 2020 BelledonneCommunications. All rights reserved.
//
import Foundation
import CallKit
import linphonesw
import AVFoundation
class CallKitProviderDelegate : NSObject
{
private let provider: CXProvider
let mCallController = CXCallController()
var tutorialContext : CallExampleContext!
init(context : CallExampleContext)
{
tutorialContext = context
let providerConfiguration = CXProviderConfiguration(localizedName: Bundle.main.infoDictionary!["CFBundleName"] as! String)
providerConfiguration.supportsVideo = true
providerConfiguration.supportedHandleTypes = [.generic]
providerConfiguration.maximumCallsPerCallGroup = 10
providerConfiguration.maximumCallGroups = 2
provider = CXProvider(configuration: providerConfiguration)
super.init()
provider.setDelegate(self, queue: nil)
}
func reportIncomingCall(call:Call?, uuid: UUID, handle: String, hasVideo: Bool) {
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type:.generic, value: handle)
update.hasVideo = hasVideo
provider.reportNewIncomingCall(with: uuid, update: update) { error in
}
}
func outgoingCall(uuid : UUID)
{
let handle = CXHandle(type: .generic, value: "Outgoing Call")
let startCallAction = CXStartCallAction(call: uuid, handle: handle)
let transaction = CXTransaction(action: startCallAction)
mCallController.request(transaction, completion: { error in
print("lalalalala")
})
}
}
extension CallKitProviderDelegate: CXProviderDelegate {
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
tutorialContext.stopCall()
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
tutorialContext.acceptCall()
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {
}
func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
tutorialContext.outgoingCallExample()
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {
}
func provider(_ provider: CXProvider, perform action: CXPlayDTMFCallAction) {
}
func provider(_ provider: CXProvider, timedOutPerforming action: CXAction) {
}
func providerDidReset(_ provider: CXProvider) {
}
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
tutorialContext.mCore.activateAudioSession(actived: true)
}
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
tutorialContext.mCore.activateAudioSession(actived: false)
}
}

View File

@@ -83,10 +83,10 @@ struct ContentView: View {
VStack(alignment: .leading) {
Toggle(isOn: $tutorialContext.audioEnabled) {
Text("Audio")
}.frame(width : 120.0)
}.frame(width : 140.0)
Toggle(isOn: $tutorialContext.videoEnabled) {
Text("Video")
}.frame(width : 120.0)
}.frame(width : 140.0)
Button(action: tutorialContext.changeVideoDevice)
{
Text(" Change camera ")
@@ -127,7 +127,7 @@ struct ContentView: View {
.background(Color.green)
}
Button(action: tutorialContext.stopCall) {
Text("Stop Call")
Text(tutorialContext.isCallIncoming ? "Decline" : "Stop Call")
.font(.largeTitle)
.foregroundColor(Color.white)
.frame(width: 180.0, height: 42.0)
@@ -141,6 +141,19 @@ struct ContentView: View {
}
.padding(.top)
}
VStack(alignment: .leading) {
Button(action: tutorialContext.outgoingCallKitCallExample) {
Text("CallKit Call")
.font(.largeTitle)
.foregroundColor(Color.white)
.frame(width: 180.0, height: 42.0)
.background(Color.green)
}
Toggle(isOn: $tutorialContext.enableCallKit) {
Text("CallKit incoming Call detection")
}.frame(width : 290.0)
}.padding(.top, 10.0)
Spacer()
Group {
Toggle(isOn: $tutorialContext.logsEnabled) {

View File

@@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UIBackgroundModes</key>
<array>
<string>voip</string>
</array>
<key>NSCameraUsageDescription</key>
<string>Camera access</string>
<key>NSMicrophoneUsageDescription</key>