2020-12-11 00:20:19 +08:00
|
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
|
|
|
|
*
|
|
|
|
|
* This file is part of Linphone TutorialCS.
|
|
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
using Linphone;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using Windows.Storage;
|
|
|
|
|
using Windows.System;
|
|
|
|
|
using Windows.UI.Xaml;
|
|
|
|
|
using Windows.UI.Xaml.Controls;
|
|
|
|
|
using Windows.UI.Xaml.Input;
|
|
|
|
|
|
|
|
|
|
namespace _01_AccountLogin
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// A really simple page for a first Login with LinphoneSDK x UWP
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed partial class MainPage : Page
|
|
|
|
|
{
|
|
|
|
|
private Core StoredCore { get; set; }
|
|
|
|
|
|
|
|
|
|
private LoggingService LoggingService { get; set; }
|
|
|
|
|
|
|
|
|
|
private Timer Timer;
|
|
|
|
|
|
|
|
|
|
public MainPage()
|
|
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
|
|
|
|
|
// Core is the main object of the SDK. You can't do much without it
|
|
|
|
|
// If you're not familiar with Linphone Core creation, see the 00_HelloWorld project.
|
|
|
|
|
LoggingService = LoggingService.Instance;
|
|
|
|
|
LoggingService.LogLevel = LogLevel.Debug;
|
|
|
|
|
LoggingService.Listener.OnLogMessageWritten = OnLog;
|
|
|
|
|
|
|
|
|
|
Factory factory = Factory.Instance;
|
|
|
|
|
|
|
|
|
|
string assetsPath = Path.Combine(Windows.ApplicationModel.Package.Current.InstalledLocation.Path, "Assets");
|
|
|
|
|
factory.TopResourcesDir = assetsPath;
|
|
|
|
|
factory.DataResourcesDir = assetsPath;
|
|
|
|
|
factory.SoundResourcesDir = Path.Combine(assetsPath, "sounds", "linphone");
|
|
|
|
|
factory.RingResourcesDir = Path.Combine(factory.SoundResourcesDir, "rings");
|
|
|
|
|
factory.ImageResourcesDir = Path.Combine(assetsPath, "images");
|
|
|
|
|
factory.MspluginsDir = ".";
|
|
|
|
|
|
|
|
|
|
Core core = factory.CreateCore("", "", IntPtr.Zero);
|
|
|
|
|
|
|
|
|
|
StoredCore = core;
|
|
|
|
|
|
2021-12-23 23:49:01 +08:00
|
|
|
|
// We need to indicate to the core where to find the root and user certificates, for future TLS exchange.
|
2020-12-11 00:20:19 +08:00
|
|
|
|
StoredCore.RootCa = Path.Combine(Windows.ApplicationModel.Package.Current.InstalledLocation.Path, "share", "Linphone", "rootca.pem");
|
|
|
|
|
StoredCore.UserCertificatesPath = ApplicationData.Current.LocalFolder.Path;
|
|
|
|
|
|
2021-12-23 23:49:01 +08:00
|
|
|
|
// In this tutorial we are going to log in and our registration state will change.
|
2020-12-11 00:20:19 +08:00
|
|
|
|
// Here we show you how to register a delegate method called every time the
|
2021-12-23 23:49:01 +08:00
|
|
|
|
// OnAccountRegistrationStateChanged callback is triggered.
|
2020-12-11 00:20:19 +08:00
|
|
|
|
StoredCore.Listener.OnAccountRegistrationStateChanged += OnAccountRegistrationStateChanged;
|
|
|
|
|
|
|
|
|
|
// Start the core after setup, and before everything else.
|
|
|
|
|
StoredCore.Start();
|
2021-12-23 23:49:01 +08:00
|
|
|
|
StoredCore.AutoIterateEnabled = true;
|
2020-12-11 00:20:19 +08:00
|
|
|
|
|
|
|
|
|
// The method Iterate must be permanently called on our core.
|
|
|
|
|
// The Iterate method runs all the waiting backgrounds tasks and poll networks notifications.
|
|
|
|
|
// Here how to setup a function called every 20ms, 20ms after the Timer object instantiation.
|
|
|
|
|
// See OnTimedEvent for more informations.
|
|
|
|
|
Timer = new Timer(OnTimedEvent, null, 20, 20);
|
|
|
|
|
|
|
|
|
|
// Setup GUI
|
|
|
|
|
Identity.Text = "sip:";
|
|
|
|
|
Password.PlaceholderText = "myPasswd";
|
|
|
|
|
LogoutGuiChanges();
|
|
|
|
|
|
|
|
|
|
// Now use the GUI to log in, and see LogInClick to see how to handle login.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Here we scheduled a callback to the Iterate method on the UI thread. While the
|
|
|
|
|
/// Linphone API calls are not thread safe, we ensure all our callbacks are done on the UI thread.
|
|
|
|
|
/// Doing this, we allow callbacks to manipulate UI without dispatcher.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private async void OnTimedEvent(object state)
|
|
|
|
|
{
|
|
|
|
|
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
|
|
|
|
{
|
|
|
|
|
StoredCore.Iterate();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Called when you click on the "Login" button.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void LogInClick(object sender, RoutedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (LogIn.IsEnabled)
|
|
|
|
|
{
|
|
|
|
|
LogIn.IsEnabled = false;
|
|
|
|
|
|
|
|
|
|
// To configure a SIP account, we need an Account object and an AuthInfo object
|
|
|
|
|
// The first one is how to connect to the proxy server, the second one stores the credentials
|
|
|
|
|
|
|
|
|
|
// Here we are creating an AuthInfo object from the identity Address and password provided by the user.
|
|
|
|
|
Address address = Factory.Instance.CreateAddress(Identity.Text);
|
|
|
|
|
// The AuthInfo can be created from the Factory as it's only a data class
|
|
|
|
|
// userID is set to null as it's the same as the username in our case
|
|
|
|
|
// ha1 is set to null as we are using the clear text password. Upon first register, the hash will be computed automatically.
|
|
|
|
|
// The realm will be determined automatically from the first register, as well as the algorithm
|
|
|
|
|
AuthInfo authInfo = Factory.Instance.CreateAuthInfo(address.Username, "", Password.Password, "", "", address.Domain);
|
|
|
|
|
// And we add it to the Core
|
|
|
|
|
StoredCore.AddAuthInfo(authInfo);
|
|
|
|
|
|
|
|
|
|
// Then we create an AccountParams object.
|
|
|
|
|
// It contains the account informations needed by the core
|
|
|
|
|
AccountParams accountParams = StoredCore.CreateAccountParams();
|
|
|
|
|
// A SIP account is identified by an identity address that we can construct from the username and domain
|
|
|
|
|
accountParams.IdentityAddress = address;
|
|
|
|
|
// We also need to configure where the proxy server is located
|
|
|
|
|
Address serverAddr = Factory.Instance.CreateAddress("sip:" + address.Domain);
|
|
|
|
|
// We use the Address object to easily set the transport protocol
|
2021-12-23 23:49:01 +08:00
|
|
|
|
if (TlsRadio.IsChecked == true) {
|
|
|
|
|
serverAddr.Transport = TransportType.Tls;
|
|
|
|
|
}
|
|
|
|
|
else if (TcpRadio.IsChecked == true)
|
|
|
|
|
{
|
|
|
|
|
serverAddr.Transport = TransportType.Tcp;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
serverAddr.Transport = TransportType.Udp;
|
|
|
|
|
}
|
2020-12-11 00:20:19 +08:00
|
|
|
|
accountParams.ServerAddress = serverAddr;
|
|
|
|
|
// If RegisterEnabled is set to true, when this account will be added to the core it will
|
|
|
|
|
// automatically try to connect.
|
|
|
|
|
accountParams.RegisterEnabled = true;
|
|
|
|
|
|
|
|
|
|
// We can now create an Account object from the AccountParams ...
|
|
|
|
|
Account account = StoredCore.CreateAccount(accountParams);
|
|
|
|
|
// ... and add it to the core, launching the connection process.
|
|
|
|
|
StoredCore.AddAccount(account);
|
|
|
|
|
// Also set the newly added account as default
|
|
|
|
|
StoredCore.DefaultAccount = account;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Called when a key is pressed and released on the login page.
|
|
|
|
|
/// If you pressed "Enter", simulate a login click.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void GridKeyUp(object sender, KeyRoutedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (VirtualKey.Enter.Equals(e.Key))
|
|
|
|
|
{
|
|
|
|
|
LogInClick(null, null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Called when you click on the "Logout" button.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void LogOutClick(object sender, RoutedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (LogOut.IsEnabled)
|
|
|
|
|
{
|
|
|
|
|
LogOut.IsEnabled = false;
|
|
|
|
|
|
|
|
|
|
// Setting RegisterEnabled to false on a connected Account object will
|
|
|
|
|
// launch the logout action.
|
|
|
|
|
Account account = StoredCore.DefaultAccount;
|
|
|
|
|
if (account != null)
|
|
|
|
|
{
|
|
|
|
|
// BUT BE CAREFUL : the Params attribute of an account is read-only
|
|
|
|
|
// You MUST Clone it :
|
|
|
|
|
AccountParams accountParams = account.Params.Clone();
|
|
|
|
|
// Then you can modify the clone :
|
|
|
|
|
accountParams.RegisterEnabled = false;
|
|
|
|
|
// And finally setting the new Params value triggers the changes, here the logout.
|
|
|
|
|
account.Params = accountParams;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// This method is called every time the RegistrationState is updated by background core's actions.
|
|
|
|
|
/// In this example we use this to update the GUI.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void OnAccountRegistrationStateChanged(Core core, Account account, RegistrationState state, string message)
|
|
|
|
|
{
|
|
|
|
|
RegistrationText.Text = "Your registration state is : " + state.ToString();
|
|
|
|
|
switch (state)
|
|
|
|
|
{
|
|
|
|
|
// If the Account was logged out, we clear the Core.
|
|
|
|
|
case RegistrationState.Cleared:
|
|
|
|
|
case RegistrationState.None:
|
|
|
|
|
StoredCore.ClearAllAuthInfo();
|
|
|
|
|
StoredCore.ClearAccounts();
|
|
|
|
|
LogoutGuiChanges();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RegistrationState.Ok:
|
|
|
|
|
LoginGuiChanges();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RegistrationState.Progress:
|
|
|
|
|
LoginInProgressGuiChanges();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RegistrationState.Failed:
|
|
|
|
|
LoginFailedChanges();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LogoutGuiChanges()
|
|
|
|
|
{
|
|
|
|
|
LogIn.IsEnabled = true;
|
|
|
|
|
LogOut.IsEnabled = false;
|
|
|
|
|
LoginText.Text = "You are logged out";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LoginFailedChanges()
|
|
|
|
|
{
|
|
|
|
|
LogIn.IsEnabled = true;
|
|
|
|
|
LogOut.IsEnabled = false;
|
|
|
|
|
LoginText.Text = "Login failed, try again";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LoginGuiChanges()
|
|
|
|
|
{
|
|
|
|
|
LogIn.IsEnabled = false;
|
|
|
|
|
LogOut.IsEnabled = true;
|
|
|
|
|
LoginText.Text = "You are logged in, with identity " + StoredCore.Identity + ".";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LoginInProgressGuiChanges()
|
|
|
|
|
{
|
|
|
|
|
LogIn.IsEnabled = false;
|
|
|
|
|
LogOut.IsEnabled = false;
|
|
|
|
|
LoginText.Text = "Login in progress, with identity " + StoredCore.Identity + ".";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnLog(LoggingService logService, string domain, LogLevel lev, string message)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder builder = new StringBuilder();
|
|
|
|
|
_ = builder.Append("Linphone-[").Append(lev.ToString()).Append("](").Append(domain).Append(")").Append(message);
|
|
|
|
|
Debug.WriteLine(builder.ToString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|