253 lines
8.0 KiB
Swift
253 lines
8.0 KiB
Swift
//
|
|
// CallExample.swift
|
|
// CallTutorial
|
|
//
|
|
// Created by QuentinArguillere on 31/07/2020.
|
|
// Copyright © 2020 BelledonneCommunications. All rights reserved.
|
|
//
|
|
|
|
import linphonesw
|
|
import AVFoundation
|
|
|
|
class CallExampleContext : ObservableObject
|
|
{
|
|
var mCore: Core! // We need a Core for... anything, basically
|
|
@Published var coreVersion: String = Core.getVersion
|
|
|
|
/*------------ Logs related variables ------------------------*/
|
|
var log : LoggingService?
|
|
var logManager : LinphoneLoggingServiceManager?
|
|
@Published var logsEnabled : Bool = true
|
|
|
|
/*------------ Call tutorial related variables ---------------*/
|
|
let mCallStateTracer = CallStateDelegate()
|
|
var mCall: Call!
|
|
var proxy_cfg : ProxyConfig!
|
|
var mVideoDevices : [String] = []
|
|
var mUsedVideoDeviceId : Int = 0
|
|
var callAlreadyStopped = false;
|
|
|
|
@Published var audioEnabled : Bool = true
|
|
@Published var videoEnabled : Bool = false
|
|
@Published var speakerEnabled : Bool = false
|
|
@Published var callRunning : Bool = false
|
|
@Published var isCallIncoming : Bool = false
|
|
@Published var dest : String = "sip:arguillq@sip.linphone.org"
|
|
|
|
let mRegistrationDelegate = LinphoneRegistrationDelegate()
|
|
@Published var id : String = "sip:peche5@sip.linphone.org"
|
|
@Published var passwd : String = "peche5"
|
|
@Published var loggedIn: Bool = false
|
|
|
|
var mProviderDelegate : CallKitProviderDelegate!
|
|
let outgoingCallName = "Outgoing call example"
|
|
let incomingCallName = "Incoming call example"
|
|
|
|
init()
|
|
{
|
|
mProviderDelegate = CallKitProviderDelegate(context : self)
|
|
mCallStateTracer.tutorialContext = self
|
|
mRegistrationDelegate.tutorialContext = self
|
|
|
|
let factory = Factory.Instance // Instanciate
|
|
|
|
logManager = LinphoneLoggingServiceManager()
|
|
logManager!.tutorialContext = self;
|
|
log = LoggingService.Instance
|
|
log!.addDelegate(delegate: logManager!)
|
|
log!.logLevel = LogLevel.Debug
|
|
factory.enableLogCollection(state: LogCollectionState.Enabled)
|
|
|
|
// Initialize Linphone Core
|
|
try? mCore = factory.createCore(configPath: "", factoryConfigPath: "", systemContext: nil)
|
|
|
|
// main loop for receiving notifications and doing background linphonecore work:
|
|
mCore.autoIterateEnabled = true
|
|
mCore.callkitEnabled = true
|
|
mCore.pushNotificationEnabled = true
|
|
try? mCore.start()
|
|
|
|
mVideoDevices = mCore.videoDevicesList
|
|
|
|
mCore.addDelegate(delegate: mCallStateTracer)
|
|
mCore.addDelegate(delegate: mRegistrationDelegate)
|
|
|
|
}
|
|
|
|
func registrationExample()
|
|
{
|
|
let factory = Factory.Instance
|
|
do {
|
|
proxy_cfg = try mCore.createProxyConfig()
|
|
let address = try factory.createAddress(addr: id)
|
|
let info = try factory.createAuthInfo(username: address.username, userid: "", passwd: passwd, ha1: "", realm: "", domain: address.domain)
|
|
mCore.addAuthInfo(info: info)
|
|
|
|
try proxy_cfg.setIdentityaddress(newValue: address)
|
|
let server_addr = "sip:" + address.domain + ";transport=tls"
|
|
try proxy_cfg.setServeraddr(newValue: server_addr)
|
|
proxy_cfg.registerEnabled = true
|
|
try mCore.addProxyConfig(config: proxy_cfg)
|
|
if ( mCore.defaultProxyConfig == nil)
|
|
{
|
|
// IMPORTANT : default proxy config setting MUST be done AFTER adding the config to the core !
|
|
mCore.defaultProxyConfig = proxy_cfg
|
|
}
|
|
|
|
} catch {
|
|
print(error)
|
|
}
|
|
}
|
|
|
|
|
|
func createCallParams() throws -> CallParams
|
|
{
|
|
let callParams = try mCore.createCallParams(call: nil)
|
|
callParams.videoEnabled = videoEnabled;
|
|
callParams.audioEnabled = audioEnabled;
|
|
|
|
return callParams
|
|
}
|
|
|
|
// Initiate a call
|
|
func outgoingCallExample()
|
|
{
|
|
do {
|
|
if (!callRunning)
|
|
{
|
|
let callDest = try Factory.Instance.createAddress(addr: dest)
|
|
// Place an outgoing call
|
|
mCall = mCore.inviteAddressWithParams(addr: callDest, params: try createCallParams())
|
|
|
|
if (mCall == nil) {
|
|
print("Could not place call to \(dest)\n")
|
|
} else {
|
|
print("Call to \(dest) is in progress...")
|
|
mProviderDelegate.outgoingCallUUID = UUID()
|
|
}
|
|
}
|
|
else
|
|
{
|
|
try mCall.update(params: createCallParams())
|
|
}
|
|
} catch {
|
|
print(error)
|
|
}
|
|
|
|
}
|
|
|
|
// Terminate a call
|
|
func stopCall()
|
|
{
|
|
if ((callRunning || isCallIncoming) && mCall.state != Call.State.End)
|
|
{
|
|
callAlreadyStopped = true;
|
|
// terminate the call
|
|
print("Terminating the call...\n")
|
|
mProviderDelegate.stopCall()
|
|
}
|
|
}
|
|
|
|
func speaker()
|
|
{
|
|
speakerEnabled = !speakerEnabled
|
|
do {
|
|
try AVAudioSession.sharedInstance().overrideOutputAudioPort(
|
|
speakerEnabled ?
|
|
AVAudioSession.PortOverride.speaker : AVAudioSession.PortOverride.none
|
|
)
|
|
} catch {
|
|
print(error)
|
|
}
|
|
}
|
|
|
|
func changeVideoDevice()
|
|
{
|
|
mUsedVideoDeviceId = (mUsedVideoDeviceId + 1) % mVideoDevices.count
|
|
|
|
do {
|
|
try mCore.setVideodevice(newValue: mVideoDevices[mUsedVideoDeviceId])
|
|
} catch {
|
|
print(error)
|
|
}
|
|
}
|
|
|
|
func acceptCall()
|
|
{
|
|
do {
|
|
try mCall.accept()
|
|
} catch {
|
|
print(error)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Callback for actions when a change in the Registration State happens
|
|
class LinphoneRegistrationDelegate: CoreDelegate {
|
|
|
|
var tutorialContext : CallExampleContext!
|
|
|
|
override func onRegistrationStateChanged(lc: Core, cfg: ProxyConfig, cstate: RegistrationState, message: String?) {
|
|
print("New registration state \(cstate) for user id \( String(describing: cfg.identityAddress?.asString()))\n")
|
|
if (cstate == .Ok)
|
|
{
|
|
if (!tutorialContext.loggedIn)
|
|
{
|
|
tutorialContext.mProviderDelegate.registerForVoIPPushes()
|
|
}
|
|
tutorialContext.loggedIn = true
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
class LinphoneLoggingServiceManager: LoggingServiceDelegate {
|
|
|
|
var tutorialContext : CallExampleContext!
|
|
|
|
override func onLogMessageWritten(logService: LoggingService, domain: String, lev: LogLevel, message: String) {
|
|
if (tutorialContext.logsEnabled)
|
|
{
|
|
print("Logging service log: \(message)s\n")
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Callback for actions when a change in the Call State happens
|
|
class CallStateDelegate: CoreDelegate {
|
|
|
|
var tutorialContext : CallExampleContext!
|
|
|
|
override func onCallStateChanged(lc: Core, call: Call, cstate: Call.State, message: String) {
|
|
print("CallTrace - \(cstate)")
|
|
if (cstate == .IncomingReceived) {
|
|
// We're being called by someone
|
|
tutorialContext.mCall = call
|
|
tutorialContext.isCallIncoming = true
|
|
|
|
} else if (cstate == .OutgoingRinging) {
|
|
// We're calling someone
|
|
tutorialContext.callRunning = true
|
|
} else if (cstate == .End) {
|
|
// Call has been terminated by any side
|
|
if (!tutorialContext.callAlreadyStopped)
|
|
{
|
|
// Report to CallKit that the call is over
|
|
tutorialContext.mProviderDelegate.stopCall()
|
|
tutorialContext.callAlreadyStopped = false
|
|
}
|
|
tutorialContext.callRunning = false
|
|
tutorialContext.isCallIncoming = false
|
|
} else if (cstate == .StreamsRunning)
|
|
{
|
|
// Call has successfully began
|
|
tutorialContext.callRunning = true
|
|
} else if (cstate == .PushIncomingReceived)
|
|
{
|
|
print("PushTrace -- push incoming")
|
|
}
|
|
}
|
|
}
|