Add CallKit basic integration for outgoing/incoming calls
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
107
swift/CallTutorial/CallTutorial/CallKitProviderDelegate.swift
Normal file
107
swift/CallTutorial/CallTutorial/CallKitProviderDelegate.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user