Files
2021-10-29 11:41:25 +02:00

239 lines
8.8 KiB
Swift

//
// OutgoingCall.swift
// OutgoingCall tutorial
//
// Created by QuentinArguillere on 08/09/2021.
// Copyright © 2021 BelledonneCommunications. All rights reserved.
//
import linphonesw
class OutgoingCallTutorialContext : ObservableObject
{
var mCore: Core!
@Published var coreVersion: String = Core.getVersion
var mAccount: Account?
var mCoreDelegate : CoreDelegate!
@Published var username : String = "user"
@Published var passwd : String = "pwd"
@Published var domain : String = "sip.example.org"
@Published var loggedIn: Bool = false
@Published var transportType : String = "TLS"
// Outgoing call related variables
@Published var callMsg : String = ""
@Published var isCallRunning : Bool = false
@Published var isVideoEnabled : Bool = false
@Published var canChangeCamera : Bool = false
@Published var remoteAddress : String = "sip:calldest@sip.linphone.org"
init()
{
LoggingService.Instance.logLevel = LogLevel.Debug
try? mCore = Factory.Instance.createCore(configPath: "", factoryConfigPath: "", systemContext: nil)
// Here we enable the video capture & display at Core level
// It doesn't mean calls will be made with video automatically,
// But it allows to use it later
mCore.videoCaptureEnabled = true
mCore.videoDisplayEnabled = true
// When enabling the video, the remote will either automatically answer the update request
// or it will ask it's user depending on it's policy.
// Here we have configured the policy to always automatically accept video requests
mCore.videoActivationPolicy!.automaticallyAccept = true
// If you don't want to automatically accept,
// you'll have to use a code similar to the one in toggleVideo to answer a received request
// If the following property is enabled, it will automatically configure created call params with video enabled
//core.videoActivationPolicy.automaticallyInitiate = true
try? mCore.start()
mCoreDelegate = CoreDelegateStub( onCallStateChanged: { (core: Core, call: Call, state: Call.State, message: String) in
// This function will be called each time a call state changes,
// which includes new incoming/outgoing calls
self.callMsg = message
if (state == .OutgoingInit) {
// First state an outgoing call will go through
} else if (state == .OutgoingProgress) {
// Right after outgoing init
} else if (state == .OutgoingRinging) {
// This state will be reached upon reception of the 180 RINGING
} else if (state == .Connected) {
// When the 200 OK has been received
} else if (state == .StreamsRunning) {
// This state indicates the call is active.
// You may reach this state multiple times, for example after a pause/resume
// or after the ICE negotiation completes
// Wait for the call to be connected before allowing a call update
self.isCallRunning = true
// Only enable toggle camera button if there is more than 1 camera
// We check if core.videoDevicesList.size > 2 because of the fake camera with static image created by our SDK (see below)
self.canChangeCamera = core.videoDevicesList.count > 2
} else if (state == .Paused) {
// When you put a call in pause, it will became Paused
self.canChangeCamera = false
} else if (state == .PausedByRemote) {
// When the remote end of the call pauses it, it will be PausedByRemote
} else if (state == .Updating) {
// When we request a call update, for example when toggling video
} else if (state == .UpdatedByRemote) {
// When the remote requests a call update
} else if (state == .Released) {
// Call state will be released shortly after the End state
self.isCallRunning = false
self.canChangeCamera = false
} else if (state == .Error) {
}
}, onAccountRegistrationStateChanged: { (core: Core, account: Account, state: RegistrationState, message: String) in
NSLog("New registration state is \(state) for user id \( String(describing: account.params?.identityAddress?.asString()))\n")
if (state == .Ok) {
self.loggedIn = true
} else if (state == .Cleared) {
self.loggedIn = false
}
})
mCore.addDelegate(delegate: mCoreDelegate)
}
func login() {
do {
var transport : TransportType
if (transportType == "TLS") { transport = TransportType.Tls }
else if (transportType == "TCP") { transport = TransportType.Tcp }
else { transport = TransportType.Udp }
let authInfo = try Factory.Instance.createAuthInfo(username: username, userid: "", passwd: passwd, ha1: "", realm: "", domain: domain)
let accountParams = try mCore.createAccountParams()
let identity = try Factory.Instance.createAddress(addr: String("sip:" + username + "@" + domain))
try! accountParams.setIdentityaddress(newValue: identity)
let address = try Factory.Instance.createAddress(addr: String("sip:" + domain))
try address.setTransport(newValue: transport)
try accountParams.setServeraddress(newValue: address)
accountParams.registerEnabled = true
mAccount = try mCore.createAccount(params: accountParams)
mCore.addAuthInfo(info: authInfo)
try mCore.addAccount(account: mAccount!)
mCore.defaultAccount = mAccount
} catch { NSLog(error.localizedDescription) }
}
func unregister()
{
if let account = mCore.defaultAccount {
let params = account.params
let clonedParams = params?.clone()
clonedParams?.registerEnabled = false
account.params = clonedParams
}
}
func delete() {
if let account = mCore.defaultAccount {
mCore.removeAccount(account: account)
mCore.clearAccounts()
mCore.clearAllAuthInfo()
}
}
func outgoingCall() {
do {
// As for everything we need to get the SIP URI of the remote and convert it to an Address
let remoteAddress = try Factory.Instance.createAddress(addr: remoteAddress)
// We also need a CallParams object
// Create call params expects a Call object for incoming calls, but for outgoing we must use null safely
let params = try mCore.createCallParams(call: nil)
// We can now configure it
// Here we ask for no encryption but we could ask for ZRTP/SRTP/DTLS
params.mediaEncryption = MediaEncryption.None
// If we wanted to start the call with video directly
//params.videoEnabled = true
// Finally we start the call
let _ = mCore.inviteAddressWithParams(addr: remoteAddress, params: params)
// Call process can be followed in onCallStateChanged callback from core listener
} catch { NSLog(error.localizedDescription) }
}
func terminateCall() {
do {
if (mCore.callsNb == 0) { return }
// If the call state isn't paused, we can get it using core.currentCall
let coreCall = (mCore.currentCall != nil) ? mCore.currentCall : mCore.calls[0]
// Terminating a call is quite simple
if let call = coreCall {
try call.terminate()
}
} catch { NSLog(error.localizedDescription) }
}
func toggleVideo() {
do {
if (mCore.callsNb == 0) { return }
let coreCall = (mCore.currentCall != nil) ? mCore.currentCall : mCore.calls[0]
// We will need the CAMERA permission for video call
if let call = coreCall {
// To update the call, we need to create a new call params, from the call object this time
let params = try mCore.createCallParams(call: call)
// Here we toggle the video state (disable it if enabled, enable it if disabled)
// Note that we are using currentParams and not params or remoteParams
// params is the object you configured when the call was started
// remote params is the same but for the remote
// current params is the real params of the call, resulting of the mix of local & remote params
params.videoEnabled = !(call.currentParams!.videoEnabled)
isVideoEnabled = params.videoEnabled
// Finally we request the call update
try call.update(params: params)
// Note that when toggling off the video, TextureViews will keep showing the latest frame displayed
}
} catch { NSLog(error.localizedDescription) }
}
func toggleCamera() {
do {
// Currently used camera
let currentDevice = mCore.videoDevice
// Let's iterate over all camera available and choose another one
for camera in mCore.videoDevicesList {
// All devices will have a "Static picture" fake camera, and we don't want to use it
if (camera != currentDevice && camera != "StaticImage: Static picture") {
try mCore.setVideodevice(newValue: camera)
break
}
}
} catch { NSLog(error.localizedDescription) }
}
func pauseOrResume() {
do {
if (mCore.callsNb == 0) { return }
let coreCall = (mCore.currentCall != nil) ? mCore.currentCall : mCore.calls[0]
if let call = coreCall {
if (call.state != Call.State.Paused && call.state != Call.State.Pausing) {
// If our call isn't paused, let's pause it
try call.pause()
} else if (call.state != Call.State.Resuming) {
// Otherwise let's resume it
try call.resume()
}
}
} catch { NSLog(error.localizedDescription) }
}
}