liblinphone_flutter/ios/Classes/LiblinphoneFlutterPlugin.swift

244 lines
8.4 KiB
Swift

import Flutter
import UIKit
public class LiblinphoneFlutterPlugin: NSObject, FlutterPlugin {
private var channel: FlutterMethodChannel!
private var registrationEventsChannel: FlutterEventSink?
private var callEventsChannel: FlutterEventSink?
private var remoteViewCache: [Int: UIView] = [:]
private var localViewCache: [Int: UIView] = [:]
private var linphoneBridge: LinphoneBridge!
private static let TAG = "LiblinphoneFlutterPlugin"
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(
name: "liblinphone_flutter",
binaryMessenger: registrar.messenger()
)
let instance = LiblinphoneFlutterPlugin()
instance.channel = channel
registrar.addMethodCallDelegate(instance, channel: channel)
// Register platform views
let remoteViewFactory = RemoteViewFactory(
messenger: registrar.messenger(),
cacher: { view in
print("[\(TAG)] Caching RemoteView")
instance.remoteViewCache[0] = view
}
)
registrar.register(
remoteViewFactory,
withId: "liblinphone_flutter.nuark.xyz/remote_view"
)
let localViewFactory = LocalViewFactory(
messenger: registrar.messenger(),
cacher: { view in
print("[\(TAG)] Caching LocalView")
instance.localViewCache[0] = view
}
)
registrar.register(
localViewFactory,
withId: "liblinphone_flutter.nuark.xyz/local_view"
)
// Setup event channels
let registrationEventChannel = FlutterEventChannel(
name: "liblinphone_flutter.nuark.xyz/registration_events",
binaryMessenger: registrar.messenger()
)
let registrationStreamHandler = EventStreamHandler(
onListen: { sink in
instance.registrationEventsChannel = sink
},
onCancel: {
instance.registrationEventsChannel = nil
}
)
registrationEventChannel.setStreamHandler(registrationStreamHandler)
let callEventChannel = FlutterEventChannel(
name: "liblinphone_flutter.nuark.xyz/call_events",
binaryMessenger: registrar.messenger()
)
let callStreamHandler = EventStreamHandler(
onListen: { sink in
instance.callEventsChannel = sink
},
onCancel: {
instance.callEventsChannel = nil
}
)
callEventChannel.setStreamHandler(callStreamHandler)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "checkPermissions":
let hasPermissions = linphoneBridge.checkPermissions()
result(hasPermissions)
case "initialize":
do {
linphoneBridge = LinphoneBridge(
remoteViewAcquisitor: { [weak self] in
return self?.acquireRemoteView()
},
localViewAcquisitor: { [weak self] in
return self?.acquireLocalView()
},
onRegistrationStateChanged: { [weak self] state in
self?.registrationEventsChannel?(state)
},
onCallStateChanged: { [weak self] state in
self?.callEventsChannel?(state)
}
)
linphoneBridge.initializeLinphone()
result(true)
} catch {
print("[\(LiblinphoneFlutterPlugin.TAG)] initialize error: \(error.localizedDescription)")
result(FlutterError(
code: "ERROR",
message: error.localizedDescription,
details: nil
))
}
case "register":
guard let args = call.arguments as? [String: Any],
let username = args["username"] as? String,
let password = args["password"] as? String,
let serverIp = args["serverIp"] as? String,
let serverPort = args["serverPort"] as? Int else {
result(FlutterError(
code: "INVALID_ARGUMENTS",
message: "Missing required arguments",
details: nil
))
return
}
do {
linphoneBridge.register(
username: username,
password: password,
serverIp: serverIp,
serverPort: serverPort
)
result(true)
} catch {
print("[\(LiblinphoneFlutterPlugin.TAG)] register error: \(error.localizedDescription)")
result(FlutterError(
code: "ERROR",
message: error.localizedDescription,
details: nil
))
}
case "unregister":
linphoneBridge.unregister()
result(true)
case "makeCall":
guard let args = call.arguments as? [String: Any],
let callTo = args["callTo"] as? String,
let isVideoEnabled = args["isVideoEnabled"] as? Bool else {
result(FlutterError(
code: "INVALID_ARGUMENTS",
message: "Missing required arguments",
details: nil
))
return
}
do {
try linphoneBridge.makeCall(callTo: callTo, isVideoEnabled: isVideoEnabled)
result(true)
} catch {
print("[\(LiblinphoneFlutterPlugin.TAG)] makeCall error: \(error.localizedDescription)")
result(FlutterError(
code: "ERROR",
message: error.localizedDescription,
details: nil
))
}
case "answerCall":
let success = linphoneBridge.answerCall()
result(success)
case "hangupCall":
let success = linphoneBridge.hangupCall()
result(success)
case "inCall":
let inCall = linphoneBridge.inCall()
result(inCall)
case "callType":
let callType = linphoneBridge.callType()
let ordinal: Int
switch callType {
case .audio:
ordinal = 0
case .video:
ordinal = 1
case .unknown:
ordinal = 2
}
result(ordinal)
case "toggleVideo":
let enabled = linphoneBridge.toggleVideo()
result(enabled)
case "toggleMicrophone":
let enabled = linphoneBridge.toggleMicrophone()
result(enabled)
case "stop":
linphoneBridge.stop()
result(true)
default:
result(FlutterMethodNotImplemented)
}
}
internal func acquireLocalView() -> UIView? {
print("[\(LiblinphoneFlutterPlugin.TAG)] acquireLocalView: \(localViewCache.count)")
return localViewCache[0]
}
internal func acquireRemoteView() -> UIView? {
print("[\(LiblinphoneFlutterPlugin.TAG)] acquireRemoteView: \(remoteViewCache.count)")
return remoteViewCache[0]
}
}
// MARK: - Event Stream Handler
class EventStreamHandler: NSObject, FlutterStreamHandler {
private let onListenCallback: (@escaping FlutterEventSink) -> Void
private let onCancelCallback: () -> Void
init(onListen: @escaping (@escaping FlutterEventSink) -> Void, onCancel: @escaping () -> Void) {
self.onListenCallback = onListen
self.onCancelCallback = onCancel
}
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
onListenCallback(events)
return nil
}
func onCancel(withArguments arguments: Any?) -> FlutterError? {
onCancelCallback()
return nil
}
}