Completely rework the chatroom tutorial to make it more intuitive : you now interact with an existing Linphone on a second phone
This commit is contained in:
@@ -25,29 +25,28 @@ class ChatRoomExampleContext : ObservableObject
|
||||
|
||||
/*-------- Chatroom tutorial related variables ---------------
|
||||
-------- "A" always initiates the chat, "B" answers --------*/
|
||||
let mIdA = "sip:peche5@sip.linphone.org", mIdB = "sip:jehan-iphone@sip.linphone.org"
|
||||
var mPasswordA = "peche5", mPasswordB = "cotcot"
|
||||
|
||||
|
||||
let mFactoryUri = "sip:conference-factory@sip.linphone.org"
|
||||
var mProxyConfigA, mProxyConfigB : ProxyConfig!
|
||||
var mProxyConfig : ProxyConfig!
|
||||
var mChatMessage : ChatMessage?
|
||||
|
||||
let mCoreChatDelegate = LinphoneCoreChatDelegate()
|
||||
let mLinphoneCoreDelegate = LinphoneCoreDelegate()
|
||||
let mChatMessageDelegate = LinphoneChatMessageTracker()
|
||||
let mChatRoomDelegate = LinphoneChatRoomStateTracker()
|
||||
let mRegistrationConfirmDelegate = LinphoneRegistrationConfirmDelegate()
|
||||
|
||||
var mChatRoomA, mChatRoomB : ChatRoom?
|
||||
@Published var chatroomState = ChatroomExampleState.Unstarted
|
||||
var mChatRoom : ChatRoom?
|
||||
|
||||
@Published var proxyConfigARegistered : Bool = false
|
||||
@Published var proxyConfigBRegistered : Bool = false
|
||||
@Published var chatroomState = ChatroomExampleState.Unstarted
|
||||
@Published var isFlexiSip : Bool = true
|
||||
@Published var textToSend: String = "msg to send"
|
||||
@Published var sReplyText: String = "msg to reply"
|
||||
@Published var sReceivedMessagesA : String = ""
|
||||
@Published var sReceivedMessagesB: String = ""
|
||||
|
||||
|
||||
@Published var sReceivedMessages : String = ""
|
||||
@Published var dest : String = "sip:arguillq@sip.linphone.org"
|
||||
@Published var id : String = "sip:quentindev@sip.linphone.org"
|
||||
@Published var passwd : String = "dev"
|
||||
@Published var loggedIn: Bool = false
|
||||
|
||||
//var fileFolderUrl : URL?
|
||||
//var fileUrl : URL?
|
||||
|
||||
func getStateAsString() -> String
|
||||
{
|
||||
switch (chatroomState)
|
||||
@@ -61,8 +60,7 @@ class ChatRoomExampleContext : ObservableObject
|
||||
init()
|
||||
{
|
||||
mChatRoomDelegate.tutorialContext = self
|
||||
mCoreChatDelegate.tutorialContext = self
|
||||
mRegistrationConfirmDelegate.tutorialContext = self
|
||||
mLinphoneCoreDelegate.tutorialContext = self
|
||||
|
||||
// Initialize Linphone Core
|
||||
try? mCore = Factory.Instance.createCore(configPath: "", factoryConfigPath: "", systemContext: nil)
|
||||
@@ -72,97 +70,61 @@ class ChatRoomExampleContext : ObservableObject
|
||||
try? mCore.start()
|
||||
|
||||
// Important ! Will notify when config are registered so that we can proceed with the chatroom creations
|
||||
mCore.addDelegate(delegate: mRegistrationConfirmDelegate)
|
||||
|
||||
// Handle chat message reception
|
||||
mCore.addDelegate(delegate: mCoreChatDelegate)
|
||||
// Also handles chat message reception
|
||||
mCore.addDelegate(delegate: mLinphoneCoreDelegate)
|
||||
|
||||
/*
|
||||
let documentsPath = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
|
||||
let myFiles = documentsPath.appendingPathComponent("TutorialFiles")
|
||||
fileUrl = myFiles?.appendingPathComponent("file_to_transfer.txt")
|
||||
do{
|
||||
try FileManager.default.createDirectory(atPath: myFiles!.path, withIntermediateDirectories: true, attributes: nil)
|
||||
try String("My file content").write(to: fileUrl!, atomically: false, encoding: .utf8)
|
||||
}catch let error as NSError{
|
||||
print("Unable to create directory",error)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
func createProxyConfigAndRegister(identity sId : String, password sPwd : String, factoryUri fUri : String) -> ProxyConfig?
|
||||
{
|
||||
let factory = Factory.Instance
|
||||
do {
|
||||
let proxy_cfg = try mCore.createProxyConfig()
|
||||
let address = try factory.createAddress(addr: sId)
|
||||
let info = try factory.createAuthInfo(username: address.username, userid: "", passwd: sPwd, 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
|
||||
proxy_cfg.conferenceFactoryUri = fUri
|
||||
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
|
||||
}
|
||||
return proxy_cfg
|
||||
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
/*
|
||||
func createProxyConfigAndRegister(identity sId : String, password sPwd : String, factoryUri fUri : String) -> ProxyConfig?
|
||||
func createProxyConfigAndRegister()
|
||||
{
|
||||
do {
|
||||
let proxy_cfg = try createAndInitializeProxyConfig(core : mCore, identity: sId, password: sPwd)
|
||||
proxy_cfg.conferenceFactoryUri = fUri
|
||||
try mCore.addProxyConfig(config: proxy_cfg)
|
||||
mProxyConfig = try createAndInitializeProxyConfig(core : mCore, identity: id, password: passwd)
|
||||
mProxyConfig.conferenceFactoryUri = mFactoryUri
|
||||
try mCore.addProxyConfig(config: mProxyConfig)
|
||||
if ( mCore.defaultProxyConfig == nil) {
|
||||
// IMPORTANT : default proxy config setting MUST be done AFTER adding the config to the core !
|
||||
mCore.defaultProxyConfig = proxy_cfg
|
||||
mCore.defaultProxyConfig = mProxyConfig
|
||||
}
|
||||
return proxy_cfg
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
return nil
|
||||
}*/
|
||||
|
||||
func registerChatRoomsProxyConfigurations()
|
||||
{
|
||||
|
||||
mProxyConfigA = createProxyConfigAndRegister(identity : mIdA, password : mPasswordA, factoryUri: mFactoryUri)!
|
||||
mProxyConfigB = createProxyConfigAndRegister(identity : mIdB, password : mPasswordB, factoryUri: mFactoryUri)!
|
||||
}
|
||||
|
||||
func createChatRoom()
|
||||
{
|
||||
// proxy configuration must first be initialized and registered
|
||||
if (!proxyConfigARegistered || !proxyConfigBRegistered || mChatRoomA != nil) { return }
|
||||
if (!loggedIn || mChatRoom != nil) { return }
|
||||
|
||||
do {
|
||||
let chatDest = [mProxyConfigB.contact!]
|
||||
let chatDest = [try Factory.Instance.createAddress(addr: dest)]
|
||||
let chatParams = try mCore.createDefaultChatRoomParams()
|
||||
if (isFlexiSip)
|
||||
{
|
||||
if (isFlexiSip) {
|
||||
chatParams.backend = ChatRoomBackend.FlexisipChat
|
||||
chatParams.encryptionEnabled = false
|
||||
chatParams.groupEnabled = false
|
||||
chatParams.subject = "Tutorial Chatroom"
|
||||
mChatRoomA = try mCore.createChatRoom(params: chatParams
|
||||
, localAddr: mProxyConfigA.contact!
|
||||
, participants: chatDest)
|
||||
mChatRoomA!.addDelegate(delegate: mChatRoomDelegate)
|
||||
mChatRoom = try mCore.createChatRoom(params: chatParams, localAddr: mProxyConfig.contact!, participants: chatDest)
|
||||
mChatRoom!.addDelegate(delegate: mChatRoomDelegate)
|
||||
// Flexisip chatroom requires a setup time. The delegate will set the state to started when it is ready.
|
||||
chatroomState = ChatroomExampleState.Starting
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
chatParams.backend = ChatRoomBackend.Basic
|
||||
mChatRoomA = try mCore.createChatRoom(params: chatParams
|
||||
, localAddr: mProxyConfigA.contact!
|
||||
, participants: chatDest)
|
||||
mChatRoom = try mCore.createChatRoom(params: chatParams, localAddr: mProxyConfig.contact!, participants: chatDest)
|
||||
// Basic chatroom do not require setup time
|
||||
chatroomState = ChatroomExampleState.Started
|
||||
|
||||
}
|
||||
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
@@ -176,7 +138,7 @@ class ChatRoomExampleContext : ObservableObject
|
||||
usleep(100000)
|
||||
}
|
||||
|
||||
if let chatRoom = self.mChatRoomA
|
||||
if let chatRoom = self.mChatRoom
|
||||
{
|
||||
do
|
||||
{
|
||||
@@ -200,67 +162,60 @@ class ChatRoomExampleContext : ObservableObject
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
func sendMsg()
|
||||
{
|
||||
if let chatRoom = mChatRoomA {
|
||||
if let chatRoom = mChatRoom {
|
||||
send(room: chatRoom, msg: textToSend)
|
||||
}
|
||||
}
|
||||
func sendReply()
|
||||
{
|
||||
if let chatRoom = mChatRoomB {
|
||||
send(room: chatRoom, msg: sReplyText)
|
||||
}
|
||||
}
|
||||
/*
|
||||
func sendFile()
|
||||
{
|
||||
do {
|
||||
let content = try mCore.createContent()
|
||||
content.filePath = fileUrl!.absoluteString
|
||||
|
||||
//mChatRoomA?.createFileTransferMessage(initialContent: <#T##Content#>)
|
||||
print(try String(contentsOf: fileUrl!, encoding: .utf8))
|
||||
}catch let error as NSError {
|
||||
print("Unable to create directory",error)
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
class LinphoneRegistrationConfirmDelegate: CoreDelegate {
|
||||
class LinphoneCoreDelegate: CoreDelegate {
|
||||
|
||||
var tutorialContext : ChatRoomExampleContext!
|
||||
|
||||
override func onRegistrationStateChanged(core lc: Core, proxyConfig cfg: ProxyConfig, state cstate: RegistrationState, message: String?) {
|
||||
print("New registration state \(cstate) for user id \( String(describing: cfg.identityAddress?.asString()))\n")
|
||||
if (cstate == RegistrationState.Ok)
|
||||
{
|
||||
if (cfg === tutorialContext.mProxyConfigA)
|
||||
{
|
||||
tutorialContext.proxyConfigARegistered = true
|
||||
}
|
||||
else if (cfg === tutorialContext.mProxyConfigB)
|
||||
{
|
||||
tutorialContext.proxyConfigBRegistered = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LinphoneCoreChatDelegate: CoreDelegate {
|
||||
var tutorialContext : ChatRoomExampleContext!
|
||||
override func onMessageReceived(core lc: Core, chatRoom room: ChatRoom, message: ChatMessage) {
|
||||
|
||||
if (tutorialContext.mChatRoomB == nil)
|
||||
{
|
||||
tutorialContext.mChatRoomB = room
|
||||
}
|
||||
if (message.contentType == "text/plain")
|
||||
{
|
||||
if (room === tutorialContext.mChatRoomA) {
|
||||
tutorialContext.sReceivedMessagesA += "\n\(message.textContent)"
|
||||
} else {
|
||||
tutorialContext.sReceivedMessagesB += "\n\(message.textContent)"
|
||||
}
|
||||
}
|
||||
|
||||
func onRegistrationStateChanged(core: Core, proxyConfig: ProxyConfig, state: RegistrationState, message: String) {
|
||||
print("New registration state \(state) for user id \( String(describing: proxyConfig.identityAddress?.asString()))\n")
|
||||
if (state == RegistrationState.Ok) {
|
||||
tutorialContext.loggedIn = true
|
||||
}
|
||||
}
|
||||
|
||||
func onMessageReceived(core lc: Core, chatRoom room: ChatRoom, message: ChatMessage) {
|
||||
if (tutorialContext.mChatRoom == nil) {
|
||||
tutorialContext.mChatRoom = room
|
||||
tutorialContext.chatroomState = ChatroomExampleState.Started
|
||||
}
|
||||
if (message.contentType == "text/plain") {
|
||||
tutorialContext.sReceivedMessages += "\n\(message.textContent)"
|
||||
}
|
||||
print(message.contents.count)
|
||||
}
|
||||
}
|
||||
|
||||
class LinphoneChatRoomStateTracker: ChatRoomDelegate {
|
||||
|
||||
var tutorialContext : ChatRoomExampleContext!
|
||||
|
||||
override func onStateChanged(chatRoom cr: ChatRoom, newState: ChatRoom.State) {
|
||||
func onStateChanged(chatRoom cr: ChatRoom, newState: ChatRoom.State) {
|
||||
if (newState == ChatRoom.State.Created)
|
||||
{
|
||||
// This will only have sense when WE are creating a flexisip chatroom.
|
||||
print("ChatRoomTrace - Chatroom ready to start")
|
||||
tutorialContext.chatroomState = ChatroomExampleState.Started
|
||||
}
|
||||
@@ -268,7 +223,7 @@ class LinphoneChatRoomStateTracker: ChatRoomDelegate {
|
||||
}
|
||||
|
||||
class LinphoneChatMessageTracker: ChatMessageDelegate {
|
||||
override func onMsgStateChanged(message msg: ChatMessage, state: ChatMessage.State) {
|
||||
func onMsgStateChanged(message msg: ChatMessage, state: ChatMessage.State) {
|
||||
print("MessageTrace - msg state changed: \(state)\n")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,25 +15,41 @@ struct ContentView: View {
|
||||
var body: some View {
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
HStack{
|
||||
Button(action: tutorialContext.registerChatRoomsProxyConfigurations)
|
||||
{
|
||||
Text("Chat Login")
|
||||
Group {
|
||||
HStack {
|
||||
Text("Identity :")
|
||||
.font(.subheadline)
|
||||
TextField("", text : $tutorialContext.id)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
}
|
||||
HStack {
|
||||
Text("Password :")
|
||||
.font(.subheadline)
|
||||
TextField("", text : $tutorialContext.passwd)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
}
|
||||
HStack {
|
||||
Button(action: tutorialContext.createProxyConfigAndRegister)
|
||||
{
|
||||
Text("Login")
|
||||
.font(.largeTitle)
|
||||
.foregroundColor(Color.white)
|
||||
.frame(width: 190.0, height: 42.0)
|
||||
.frame(width: 90.0, height: 42.0)
|
||||
.background(Color.gray)
|
||||
}.disabled(tutorialContext.proxyConfigBRegistered && tutorialContext.proxyConfigBRegistered)
|
||||
VStack{
|
||||
Text(tutorialContext.proxyConfigARegistered ? "A logged in" :"A not registered")
|
||||
.font(.footnote)
|
||||
.foregroundColor(tutorialContext.proxyConfigARegistered ? Color.green : Color.black)
|
||||
Text(tutorialContext.proxyConfigBRegistered ? "B logged in" :"B not registered")
|
||||
.font(.footnote)
|
||||
.foregroundColor(tutorialContext.proxyConfigBRegistered ? Color.green : Color.black)
|
||||
}
|
||||
Text("Login State : ")
|
||||
.font(.footnote)
|
||||
Text(tutorialContext.loggedIn ? "Logged in" : "Unregistered")
|
||||
.font(.footnote)
|
||||
.foregroundColor(tutorialContext.loggedIn ? Color.green : Color.black)
|
||||
}
|
||||
}
|
||||
|
||||
HStack {
|
||||
Text("Call destination :")
|
||||
TextField("", text : $tutorialContext.dest)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
}
|
||||
.padding(.top, 5)
|
||||
HStack {
|
||||
VStack() {
|
||||
Toggle(isOn: $tutorialContext.isFlexiSip) {
|
||||
@@ -55,13 +71,13 @@ struct ContentView: View {
|
||||
.foregroundColor(Color.white)
|
||||
.frame(width: 100.0, height: 82.0)
|
||||
.background(Color.gray)
|
||||
}.disabled(!tutorialContext.proxyConfigBRegistered || !tutorialContext.proxyConfigBRegistered)
|
||||
}.disabled(!tutorialContext.loggedIn)
|
||||
}
|
||||
HStack {
|
||||
VStack {
|
||||
Text("Chat received by A").bold()
|
||||
Text("Chat received").bold()
|
||||
ScrollView {
|
||||
Text(tutorialContext.sReceivedMessagesA)
|
||||
Text(tutorialContext.sReceivedMessages)
|
||||
.font(.footnote)
|
||||
.frame(width : 160)
|
||||
}.border(Color.gray)
|
||||
@@ -79,26 +95,6 @@ struct ContentView: View {
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
VStack {
|
||||
Text("Chat received by B").bold()
|
||||
ScrollView {
|
||||
Text(tutorialContext.sReceivedMessagesB)
|
||||
.font(.footnote)
|
||||
.frame(width : 160)
|
||||
}.border(Color.gray)
|
||||
HStack {
|
||||
TextField("Reply text", text : $tutorialContext.sReplyText)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
Button(action: tutorialContext.sendReply)
|
||||
{
|
||||
Text("Reply")
|
||||
.font(.callout)
|
||||
.foregroundColor(Color.white)
|
||||
.frame(width: 50.0, height: 30.0)
|
||||
.background(Color.gray)
|
||||
}.disabled(!tutorialContext.proxyConfigBRegistered || !tutorialContext.proxyConfigBRegistered)
|
||||
}
|
||||
}
|
||||
}.padding(.top)
|
||||
Group {
|
||||
Spacer()
|
||||
|
||||
Reference in New Issue
Block a user