Files
linphone-tutorials/ios/swift/4-CallKitTutorial/CallKitTutorial/LinphoneAsyncHelper.swift

203 lines
6.2 KiB
Swift

//
// LinphoneAsyncWrapper.swift
// CallKitTutorial
//
// Created by CD on 13/09/2023.
// Copyright © 2023 BelledonneCommunications. All rights reserved.
//
import Foundation
import Combine
import linphonesw
var coreQueue : DispatchQueue = DispatchQueue(label:"core.queue")
var cancellables = Set<AnyCancellable>()
// A publisher object that can old one or many LinphoneObject objects.
public class LinphoneObjectsPublisher <T> : Publisher {
public typealias Output = T
public typealias Failure = Error
let passThroughSubject = PassthroughSubject<Output, Failure>()
public func receive<S>(subscriber: S) where S : Subscriber, S.Failure == Failure, S.Input == Output {
passThroughSubject.receive(subscriber: subscriber)
}
public func send(completion: Subscribers.Completion<Failure>) {
passThroughSubject.send(completion: completion)
}
@discardableResult
public func postOnMainQueue(onError :@escaping ((Error) -> Void) = {_ in }, receiveValue:@escaping ((Output) -> Void)) -> LinphoneObjectsPublisher <T>{
doOnQueue(onError,receiveValue,queue: DispatchQueue.main)
return self
}
@discardableResult
public func postOnCoreQueue(onError :@escaping ((Error) -> Void) = {_ in }, receiveValue:@escaping ((Output) -> Void)) -> LinphoneObjectsPublisher <T>{
doOnQueue(onError,receiveValue,queue: coreQueue)
return self
}
private func doOnQueue(_ onError :@escaping ((Error) -> Void) = {_ in }, _ receiveValue:@escaping ((Output) -> Void), queue:DispatchQueue) {
passThroughSubject.receive(on:queue)
.sink { error in
onError(error as! Error)
} receiveValue: { result in
receiveValue(result)
}.store(in: &cancellables)
}
var savedReference : Any? = nil // Used when a reference is needed to avoid object from beeing GCd (example delegate stubs)
convenience init (reference: Any) {
self.init()
savedReference = reference
}
}
public class LinphoneAsyncHelper {
static func postOnCoreQueue(lambda : @escaping ()->()) {
coreQueue.async {
lambda()
}
}
static func postOnMainQueue(lambda : @escaping()->()) {
DispatchQueue.main.async {
lambda()
}
}
/*
// Creates a publisher from the object created by the action passed as parameter
// For example if passed a create core call this function will create the LinphoneObject Core on core queue, and created object will be published through the built publisher
func createLinphoneObjectWithPublisher<LinphoneObject>(createAction:@escaping()throws -> LinphoneObject ) -> LinphoneObjectsPublisher<LinphoneObject> {
let publisher = LinphoneObjectsPublisher<LinphoneObject>()
coreQueue.async {
do {
publisher.passThroughSubject.send(try createAction())
} catch {
publisher.send(completion: .failure(error))
}
}
return publisher
}
*/
}
extension Core {
// Methods below would generated by a script similar to the one that creates LinphoneWrapper
public func createAccountRegistrationStateChangedPublisher() -> LinphoneObjectsPublisher<(core:Core, account:Account, state:RegistrationState, message:String)> {
let publisher = LinphoneObjectsPublisher<(core:Core, account:Account, state:RegistrationState, message:String)>()
let coreDelegate = CoreDelegateStub (
onAccountRegistrationStateChanged: { (core: Core, account: Account, state: RegistrationState, message: String) in
publisher.passThroughSubject.send((core,account,state,message))
})
publisher.savedReference = coreDelegate
addDelegate(delegate: coreDelegate)
return publisher
}
public func createOnCallStateChangedPublisher() -> LinphoneObjectsPublisher<(core: Core, call: Call, state: Call.State, message: String)> {
let publisher = LinphoneObjectsPublisher<(core: Core, call: Call, state: Call.State, message: String)>()
let coreDelegate = CoreDelegateStub (
onCallStateChanged: { (core: Core, call: Call, state: Call.State, message: String) in
publisher.passThroughSubject.send((core,call,state,message))
})
publisher.savedReference = coreDelegate
addDelegate(delegate: coreDelegate)
return publisher
}
// ...
}
/*
extension Factory {
static var linphoneObjectsPublishers = [String:LinphoneObjectsPublisher<Factory>]()
var publisher: LinphoneObjectsPublisher<Factory> {
get {
let ref = String(format: "%p", unsafeBitCast(self, to: Int.self))
if (Factory.linphoneObjectsPublishers[ref] == nil) {
let publisher = LinphoneObjectsPublisher<Factory>()
Factory.linphoneObjectsPublishers[ref] = publisher
}
coreQueue.async {
Factory.linphoneObjectsPublishers[ref]!.passThroughSubject.send(self)
}
return Factory.linphoneObjectsPublishers[ref]!
}
set(newValue) {
let ref = String(format: "%p", unsafeBitCast(self, to: Int.self))
Factory.linphoneObjectsPublishers[ref] = newValue
}
}
}
extension LinphoneObject {
static var linphoneObjectsPublishers = [String:LinphoneObjectsPublisher<LinphoneObject>]()
private func refFromSelf() -> String {
return String(format: "%p", unsafeBitCast(self, to: Int.self))
}
var publisher: LinphoneObjectsPublisher<LinphoneObject> {
get {
let ref = refFromSelf()
if (LinphoneObject.linphoneObjectsPublishers[ref] == nil) {
let publisher = LinphoneObjectsPublisher<LinphoneObject>()
LinphoneObject.linphoneObjectsPublishers[ref] = publisher
}
coreQueue.async {
LinphoneObject.linphoneObjectsPublishers[ref]!.passThroughSubject.send(self)
}
return LinphoneObject.linphoneObjectsPublishers[ref]!
}
set(newValue) {
let ref = refFromSelf()
LinphoneObject.linphoneObjectsPublishers[ref] = newValue
}
}
}
// Could not find a way to put the below inside the generic LinphoneObject extension
extension Factory {
func postOnCoreQueue(lambda:@escaping ((Factory) -> Void)) {
publisher.postOnCoreQueue { result in
lambda(result as! Factory)
}
}
func postOnMainQueue(lambda:@escaping ((Factory) -> Void)) {
publisher.postOnMainQueue { result in
lambda(result as! Factory)
}
}
}
extension Core {
func postOnCoreQueue(lambda:@escaping ((Core) -> Void)) {
publisher.postOnCoreQueue { result in
lambda(result as! Core)
}
}
func postOnMainQueue(lambda:@escaping ((Core) -> Void)) {
publisher.postOnMainQueue { result in
lambda(result as! Core)
}
}
}
// .. add extensions to other needed objects, or have this generated in the wrapper
*/