Compare commits
3 Commits
master
...
feature/ad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfad6c515f | ||
|
|
28c66b6398 | ||
|
|
53a8bbba8f |
1
qt/00_HelloWorld/.gitignore
vendored
Normal file
1
qt/00_HelloWorld/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
build/
|
||||||
44
qt/00_HelloWorld/CMakeLists.txt
Normal file
44
qt/00_HelloWorld/CMakeLists.txt
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.22)
|
||||||
|
|
||||||
|
project(00_HelloWorld LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
find_package(Qt5 REQUIRED COMPONENTS Core Gui Qml Quick)
|
||||||
|
find_package(LinphoneCxx REQUIRED)
|
||||||
|
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
SET(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
"src/main.cpp"
|
||||||
|
"src/CoreManager.cpp"
|
||||||
|
)
|
||||||
|
set(QRC_RESOURCES resources.qrc)
|
||||||
|
set(QML_SOURCES)
|
||||||
|
file(STRINGS ${QRC_RESOURCES} QRC_RESOURCES_CONTENT)
|
||||||
|
foreach(line ${QRC_RESOURCES_CONTENT})
|
||||||
|
set(result)
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"^[ \t]*<[ \t]*file[ \t]*>[ \t]*(.+\\.[a-z]+)[ \t]*<[ \t]*/[ \t]*file[ \t]*>[ \t]*$"
|
||||||
|
"\\1"
|
||||||
|
result
|
||||||
|
"${line}"
|
||||||
|
)
|
||||||
|
string(REGEX MATCH "\\.[a-z]+$" is_ui ${result})
|
||||||
|
if(NOT ${is_ui} STREQUAL "")
|
||||||
|
list(APPEND QML_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${result}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
add_executable(00_HelloWorld ${SOURCES} ${QML_SOURCES} ${QRC_RESOURCES})
|
||||||
|
|
||||||
|
target_include_directories(00_HelloWorld PRIVATE ${LINPHONECXX_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(00_HelloWorld PRIVATE Qt5::Core Qt5::Gui Qt5::Qml Qt5::Quick ${LINPHONECXX_LIBRARIES})
|
||||||
|
|
||||||
|
set_target_properties(00_HelloWorld PROPERTIES AUTORCC ON)
|
||||||
|
set_target_properties(00_HelloWorld PROPERTIES
|
||||||
|
WIN32_EXECUTABLE ON
|
||||||
|
MACOSX_BUNDLE ON
|
||||||
|
)
|
||||||
15
qt/00_HelloWorld/README.md
Normal file
15
qt/00_HelloWorld/README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Hello World tutorial
|
||||||
|
|
||||||
|
The purpose of this tutorial is to explain how to build a Qt app depending on the Linphone SDK and to create the `Core` object that all our APIs depends on.
|
||||||
|
|
||||||
|
The user interface will only display the `Core`'s version, but in the next tutorial you will learn how to use it to login your SIP account.
|
||||||
|
|
||||||
|
|
||||||
|
## How to build
|
||||||
|
|
||||||
|
In the following instructions, replace **<PATH-TO-SDK>** by the real path where your SDK is located, e.g. *~/projects/linphone-sdk/build-default/linphone-sdk/desktop/*
|
||||||
|
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DCMAKE_PREFIX_PATH=<PATH-TO-SDK>
|
||||||
|
cmake --build .
|
||||||
5
qt/00_HelloWorld/resources.qrc
Normal file
5
qt/00_HelloWorld/resources.qrc
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>ui/MainPage.qml</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
32
qt/00_HelloWorld/src/CoreManager.cpp
Normal file
32
qt/00_HelloWorld/src/CoreManager.cpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#include "CoreManager.hpp"
|
||||||
|
|
||||||
|
CoreManager *CoreManager::mInstance = nullptr;
|
||||||
|
|
||||||
|
CoreManager::CoreManager()
|
||||||
|
{
|
||||||
|
// Create a core from the factory.
|
||||||
|
mCore = linphone::Factory::get()->createCore("", "", nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreManager::~CoreManager()
|
||||||
|
{
|
||||||
|
mCore = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::init()
|
||||||
|
{
|
||||||
|
if (mInstance)
|
||||||
|
return;
|
||||||
|
mInstance = new CoreManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreManager *CoreManager::getInstance()
|
||||||
|
{
|
||||||
|
return mInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString CoreManager::getVersion() const
|
||||||
|
{
|
||||||
|
// Get the version from the core.
|
||||||
|
return QString::fromStdString(mCore->getVersion());
|
||||||
|
}
|
||||||
25
qt/00_HelloWorld/src/CoreManager.hpp
Normal file
25
qt/00_HelloWorld/src/CoreManager.hpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QtCore>
|
||||||
|
|
||||||
|
#include <linphone++/linphone.hh>
|
||||||
|
|
||||||
|
class CoreManager : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QString version READ getVersion CONSTANT)
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void init();
|
||||||
|
static CoreManager *getInstance();
|
||||||
|
|
||||||
|
QString getVersion() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CoreManager();
|
||||||
|
~CoreManager();
|
||||||
|
|
||||||
|
std::shared_ptr<linphone::Core> mCore = nullptr;
|
||||||
|
|
||||||
|
static CoreManager *mInstance;
|
||||||
|
};
|
||||||
28
qt/00_HelloWorld/src/main.cpp
Normal file
28
qt/00_HelloWorld/src/main.cpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#include <QDir>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QQmlApplicationEngine>
|
||||||
|
#include <QQmlContext>
|
||||||
|
|
||||||
|
#include "CoreManager.hpp"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
QGuiApplication app(argc, argv);
|
||||||
|
app.setOrganizationName("Belledonne Communications");
|
||||||
|
app.setOrganizationDomain("belledonne-communications.com");
|
||||||
|
app.setApplicationName(QFileInfo(app.applicationFilePath()).baseName());
|
||||||
|
|
||||||
|
QQmlApplicationEngine engine;
|
||||||
|
engine.load(QUrl("qrc:/ui/MainPage.qml"));
|
||||||
|
if (engine.rootObjects().isEmpty())
|
||||||
|
qFatal("Unable to open main window.");
|
||||||
|
|
||||||
|
// Initialize the CoreManager singleton and add it to the Qml context.
|
||||||
|
CoreManager::init();
|
||||||
|
auto coreManager = CoreManager::getInstance();
|
||||||
|
QQmlContext *ctx = engine.rootContext();
|
||||||
|
ctx->setContextProperty("coreManager", coreManager);
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
18
qt/00_HelloWorld/ui/MainPage.qml
Normal file
18
qt/00_HelloWorld/ui/MainPage.qml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
|
||||||
|
ApplicationWindow {
|
||||||
|
id: window
|
||||||
|
visible: true
|
||||||
|
|
||||||
|
title: "Hello World"
|
||||||
|
width: 640
|
||||||
|
height: 480
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: versionText
|
||||||
|
text: "Hello world, Linphone core version is " + coreManager.version // Get the version from the core manager.
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
1
qt/01_AccountLogin/.gitignore
vendored
Normal file
1
qt/01_AccountLogin/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
build/
|
||||||
52
qt/01_AccountLogin/CMakeLists.txt
Normal file
52
qt/01_AccountLogin/CMakeLists.txt
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.22)
|
||||||
|
|
||||||
|
project(01_AccountLogin LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
find_package(Qt5 REQUIRED COMPONENTS Core Gui Qml Quick)
|
||||||
|
find_package(LinphoneCxx REQUIRED)
|
||||||
|
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
SET(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
"src/main.cpp"
|
||||||
|
"src/App.cpp"
|
||||||
|
"src/CoreHandler.cpp"
|
||||||
|
"src/CoreListener.cpp"
|
||||||
|
"src/CoreManager.cpp"
|
||||||
|
)
|
||||||
|
set(QRC_RESOURCES resources.qrc)
|
||||||
|
set(QML_SOURCES)
|
||||||
|
file(STRINGS ${QRC_RESOURCES} QRC_RESOURCES_CONTENT)
|
||||||
|
foreach(line ${QRC_RESOURCES_CONTENT})
|
||||||
|
set(result)
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"^[ \t]*<[ \t]*file[ \t]*>[ \t]*(.+\\.[a-z]+)[ \t]*<[ \t]*/[ \t]*file[ \t]*>[ \t]*$"
|
||||||
|
"\\1"
|
||||||
|
result
|
||||||
|
"${line}"
|
||||||
|
)
|
||||||
|
string(REGEX MATCH "\\.[a-z]+$" is_ui ${result})
|
||||||
|
if(NOT ${is_ui} STREQUAL "")
|
||||||
|
list(APPEND QML_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${result}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
get_filename_component(SDK_PATH "${CMAKE_PREFIX_PATH}" REALPATH)
|
||||||
|
find_path(MSPLUGINS_PATH "plugins" PATH_SUFFIXES "lib/mediastreamer" "lib64/mediastreamer" REQUIRED)
|
||||||
|
set(MSPLUGINS_PATH "${MSPLUGINS_PATH}/plugins")
|
||||||
|
|
||||||
|
add_executable(01_AccountLogin ${SOURCES} ${QML_SOURCES} ${QRC_RESOURCES})
|
||||||
|
|
||||||
|
target_compile_definitions(01_AccountLogin PRIVATE "SDK_PATH=\"${SDK_PATH}\"" "MSPLUGINS_PATH=\"${MSPLUGINS_PATH}\"")
|
||||||
|
target_include_directories(01_AccountLogin PRIVATE ${LINPHONECXX_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(01_AccountLogin PRIVATE Qt5::Core Qt5::Gui Qt5::Qml Qt5::Quick ${LINPHONECXX_LIBRARIES})
|
||||||
|
|
||||||
|
set_target_properties(01_AccountLogin PROPERTIES AUTORCC ON)
|
||||||
|
set_target_properties(01_AccountLogin PROPERTIES
|
||||||
|
WIN32_EXECUTABLE ON
|
||||||
|
MACOSX_BUNDLE ON
|
||||||
|
)
|
||||||
15
qt/01_AccountLogin/README.md
Normal file
15
qt/01_AccountLogin/README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Account Login tutorial
|
||||||
|
|
||||||
|
This project will walk you through the different steps of logging in and out of a SIP account.
|
||||||
|
|
||||||
|
If you do not yet have a SIP account, please create one here : https://www.linphone.org/freesip/home
|
||||||
|
|
||||||
|
|
||||||
|
## How to build
|
||||||
|
|
||||||
|
In the following instructions, replace **<PATH-TO-SDK>** by the real path where your SDK is located, e.g. *~/projects/linphone-sdk/build-default/linphone-sdk/desktop/*
|
||||||
|
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DCMAKE_PREFIX_PATH=<PATH-TO-SDK>
|
||||||
|
cmake --build .
|
||||||
6
qt/01_AccountLogin/resources.qrc
Normal file
6
qt/01_AccountLogin/resources.qrc
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>ui/MainPage.qml</file>
|
||||||
|
<file>ui/RegistrationPage.qml</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
47
qt/01_AccountLogin/src/App.cpp
Normal file
47
qt/01_AccountLogin/src/App.cpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#include <QDir>
|
||||||
|
#include <QQmlContext>
|
||||||
|
|
||||||
|
#include "App.hpp"
|
||||||
|
#include "CoreManager.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace linphone;
|
||||||
|
|
||||||
|
App::App(int &argc, char *argv[]) : QGuiApplication(argc, argv)
|
||||||
|
{
|
||||||
|
setOrganizationName("Belledonne Communications");
|
||||||
|
setOrganizationDomain("belledonne-communications.com");
|
||||||
|
setApplicationName(QFileInfo(applicationFilePath()).baseName());
|
||||||
|
}
|
||||||
|
|
||||||
|
App::~App()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::init()
|
||||||
|
{
|
||||||
|
registerTypes();
|
||||||
|
|
||||||
|
mEngine = new QQmlApplicationEngine();
|
||||||
|
mEngine->load(QUrl("qrc:/ui/MainPage.qml"));
|
||||||
|
if (mEngine->rootObjects().isEmpty())
|
||||||
|
qFatal("Unable to open main window.");
|
||||||
|
|
||||||
|
// Initialize the CoreManager singleton and add it to the Qml context.
|
||||||
|
CoreManager::init(this);
|
||||||
|
auto coreManager = CoreManager::getInstance();
|
||||||
|
QQmlContext *ctx = mEngine->rootContext();
|
||||||
|
ctx->setContextProperty("coreManager", coreManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::stop()
|
||||||
|
{
|
||||||
|
CoreManager::uninit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::registerTypes()
|
||||||
|
{
|
||||||
|
qRegisterMetaType<string>();
|
||||||
|
qRegisterMetaType<RegistrationState>();
|
||||||
|
qRegisterMetaType<shared_ptr<Account>>();
|
||||||
|
}
|
||||||
25
qt/01_AccountLogin/src/App.hpp
Normal file
25
qt/01_AccountLogin/src/App.hpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QQmlApplicationEngine>
|
||||||
|
|
||||||
|
#include <linphone++/linphone.hh>
|
||||||
|
|
||||||
|
class App : public QGuiApplication
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
App(int &argc, char *argv[]);
|
||||||
|
~App();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void registerTypes();
|
||||||
|
|
||||||
|
QQmlApplicationEngine *mEngine = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(std::string);
|
||||||
|
Q_DECLARE_METATYPE(linphone::RegistrationState);
|
||||||
|
Q_DECLARE_METATYPE(std::shared_ptr<linphone::Account>);
|
||||||
69
qt/01_AccountLogin/src/CoreHandler.cpp
Normal file
69
qt/01_AccountLogin/src/CoreHandler.cpp
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "CoreHandler.hpp"
|
||||||
|
#include "CoreListener.hpp"
|
||||||
|
#include "CoreManager.hpp"
|
||||||
|
|
||||||
|
CoreHandler::CoreHandler()
|
||||||
|
{
|
||||||
|
mCoreListener = std::make_shared<CoreListener>();
|
||||||
|
connectTo(mCoreListener.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreHandler::setListener(std::shared_ptr<linphone::Core> core)
|
||||||
|
{
|
||||||
|
core->addListener(mCoreListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreHandler::removeListener(std::shared_ptr<linphone::Core> core)
|
||||||
|
{
|
||||||
|
core->removeListener(mCoreListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreHandler::onAccountRegistrationStateChanged(const std::shared_ptr<linphone::Core> &, const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state, const std::string &message)
|
||||||
|
{
|
||||||
|
emit registrationStateChanged(account, state, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreHandler::onGlobalStateChanged(const std::shared_ptr<linphone::Core> &, linphone::GlobalState state, const std::string &message)
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case linphone::GlobalState::On:
|
||||||
|
qInfo() << "Core is running " << QString::fromStdString(message);
|
||||||
|
break;
|
||||||
|
case linphone::GlobalState::Off:
|
||||||
|
qInfo() << "Core is stopped " << QString::fromStdString(message);
|
||||||
|
emit coreStopped();
|
||||||
|
break;
|
||||||
|
case linphone::GlobalState::Startup:
|
||||||
|
qInfo() << "Core is starting" << QString::fromStdString(message);
|
||||||
|
emit coreStarting();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreHandler::connectTo(CoreListener *listener)
|
||||||
|
{
|
||||||
|
connect(listener, &CoreListener::accountRegistrationStateChanged, this, &CoreHandler::onAccountRegistrationStateChanged);
|
||||||
|
connect(listener, &CoreListener::globalStateChanged, this, &CoreHandler::onGlobalStateChanged);
|
||||||
|
}
|
||||||
47
qt/01_AccountLogin/src/CoreHandler.hpp
Normal file
47
qt/01_AccountLogin/src/CoreHandler.hpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <linphone++/linphone.hh>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class CoreListener;
|
||||||
|
|
||||||
|
class CoreHandler : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
CoreHandler();
|
||||||
|
|
||||||
|
void setListener(std::shared_ptr<linphone::Core> core);
|
||||||
|
void removeListener(std::shared_ptr<linphone::Core> core);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void coreStarting();
|
||||||
|
void coreStopped();
|
||||||
|
void registrationStateChanged(const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state, const std::string &message);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onAccountRegistrationStateChanged(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state, const std::string &message);
|
||||||
|
void onGlobalStateChanged(const std::shared_ptr<linphone::Core> &core, linphone::GlobalState gstate, const std::string &message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void connectTo(CoreListener *listener);
|
||||||
|
std::shared_ptr<CoreListener> mCoreListener;
|
||||||
|
};
|
||||||
32
qt/01_AccountLogin/src/CoreListener.cpp
Normal file
32
qt/01_AccountLogin/src/CoreListener.cpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CoreListener.hpp"
|
||||||
|
|
||||||
|
CoreListener::CoreListener(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreListener::onAccountRegistrationStateChanged(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state, const std::string &message)
|
||||||
|
{
|
||||||
|
emit accountRegistrationStateChanged(core, account, state, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreListener::onGlobalStateChanged(const std::shared_ptr<linphone::Core> &core, linphone::GlobalState gstate, const std::string &message)
|
||||||
|
{
|
||||||
|
emit globalStateChanged(core, gstate, message);
|
||||||
|
}
|
||||||
37
qt/01_AccountLogin/src/CoreListener.hpp
Normal file
37
qt/01_AccountLogin/src/CoreListener.hpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <linphone++/linphone.hh>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class CoreListener : public QObject, public linphone::CoreListener
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
CoreListener(QObject *parent = nullptr);
|
||||||
|
virtual ~CoreListener() = default;
|
||||||
|
|
||||||
|
virtual void onAccountRegistrationStateChanged(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state, const std::string &message) override;
|
||||||
|
virtual void onGlobalStateChanged(const std::shared_ptr<linphone::Core> &core, linphone::GlobalState gstate, const std::string &message) override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void accountRegistrationStateChanged(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state, const std::string &message);
|
||||||
|
void globalStateChanged(const std::shared_ptr<linphone::Core> &core, linphone::GlobalState gstate, const std::string &message);
|
||||||
|
};
|
||||||
235
qt/01_AccountLogin/src/CoreManager.cpp
Normal file
235
qt/01_AccountLogin/src/CoreManager.cpp
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "CoreHandler.hpp"
|
||||||
|
#include "CoreManager.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace linphone;
|
||||||
|
|
||||||
|
CoreManager *CoreManager::mInstance = nullptr;
|
||||||
|
|
||||||
|
CoreManager::CoreManager(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
mHandler = QSharedPointer<CoreHandler>::create();
|
||||||
|
CoreHandler *coreHandler = mHandler.get();
|
||||||
|
QObject::connect(coreHandler, &CoreHandler::coreStarting, this, &CoreManager::startIterate, Qt::QueuedConnection);
|
||||||
|
QObject::connect(coreHandler, &CoreHandler::coreStopped, this, &CoreManager::stopIterate, Qt::QueuedConnection);
|
||||||
|
QObject::connect(coreHandler, &CoreHandler::registrationStateChanged, this, &CoreManager::onRegistrationStateChanged, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
// Delay the creation of the core so that the CoreManager instance is
|
||||||
|
// already set.
|
||||||
|
QTimer::singleShot(10, [this]()
|
||||||
|
{ createLinphoneCore(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreManager::~CoreManager()
|
||||||
|
{
|
||||||
|
mHandler->removeListener(mCore);
|
||||||
|
mHandler = nullptr;
|
||||||
|
mCore = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::init(QObject *parent)
|
||||||
|
{
|
||||||
|
if (mInstance)
|
||||||
|
return;
|
||||||
|
mInstance = new CoreManager(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::uninit()
|
||||||
|
{
|
||||||
|
if (mInstance)
|
||||||
|
{
|
||||||
|
mInstance->stopIterate();
|
||||||
|
auto core = mInstance->mCore;
|
||||||
|
delete mInstance;
|
||||||
|
mInstance = nullptr;
|
||||||
|
core->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreManager *CoreManager::getInstance()
|
||||||
|
{
|
||||||
|
return mInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::startIterate()
|
||||||
|
{
|
||||||
|
// Start a timer to call the core iterate every 20 ms.
|
||||||
|
mIterateTimer = new QTimer(this);
|
||||||
|
mIterateTimer->setInterval(20);
|
||||||
|
QObject::connect(mIterateTimer, &QTimer::timeout, this, &CoreManager::iterate);
|
||||||
|
qInfo() << QStringLiteral("Start iterate");
|
||||||
|
mIterateTimer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::stopIterate()
|
||||||
|
{
|
||||||
|
qInfo() << QStringLiteral("Stop iterate");
|
||||||
|
mIterateTimer->stop();
|
||||||
|
mIterateTimer->deleteLater(); // Allow the timer to continue its stuff
|
||||||
|
mIterateTimer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::login(QString identity, QString password, QString transport)
|
||||||
|
{
|
||||||
|
if (mLoginButtonEnabled)
|
||||||
|
{
|
||||||
|
setProperty("loginButtonEnabled", 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.
|
||||||
|
shared_ptr<Address> address = Factory::get()->createAddress(identity.toStdString());
|
||||||
|
|
||||||
|
// 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
|
||||||
|
shared_ptr<AuthInfo> authInfo = Factory::get()->createAuthInfo(address->getUsername(), "", password.toStdString(), "", "", address->getDomain());
|
||||||
|
// And we add it to the Core
|
||||||
|
mCore->addAuthInfo(authInfo);
|
||||||
|
|
||||||
|
// Then we create an AccountParams object.
|
||||||
|
// It contains the account informations needed by the core
|
||||||
|
shared_ptr<AccountParams> accountParams = mCore->createAccountParams();
|
||||||
|
// A SIP account is identified by an identity address that we can construct from the username and domain
|
||||||
|
accountParams->setIdentityAddress(address);
|
||||||
|
// We also need to configure where the proxy server is located
|
||||||
|
shared_ptr<Address> serverAddr = Factory::get()->createAddress("sip:" + address->getDomain());
|
||||||
|
// We use the Address object to easily set the transport protocol
|
||||||
|
if (transport == "tls")
|
||||||
|
{
|
||||||
|
serverAddr->setTransport(TransportType::Tls);
|
||||||
|
}
|
||||||
|
else if (transport == "tcp")
|
||||||
|
{
|
||||||
|
serverAddr->setTransport(TransportType::Tcp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serverAddr->setTransport(TransportType::Udp);
|
||||||
|
}
|
||||||
|
accountParams->setServerAddress(serverAddr);
|
||||||
|
// If enableRegister is set to true, when this account will be added to the core it will
|
||||||
|
// automatically try to connect.
|
||||||
|
accountParams->enableRegister(true);
|
||||||
|
|
||||||
|
// We can now create an Account object from the AccountParams ...
|
||||||
|
shared_ptr<Account> account = mCore->createAccount(accountParams);
|
||||||
|
// ... and add it to the core, launching the connection process.
|
||||||
|
mCore->addAccount(account);
|
||||||
|
// Also set the newly added account as default
|
||||||
|
mCore->setDefaultAccount(account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::logout()
|
||||||
|
{
|
||||||
|
if (mLogoutButtonEnabled)
|
||||||
|
{
|
||||||
|
setProperty("logoutButtonEnabled", false);
|
||||||
|
|
||||||
|
// Setting enableRegister to false on a connected Account object will
|
||||||
|
// launch the logout action.
|
||||||
|
shared_ptr<Account> account = mCore->getDefaultAccount();
|
||||||
|
if (account)
|
||||||
|
{
|
||||||
|
// BUT BE CAREFUL : the Params of an account are read-only
|
||||||
|
// You MUST Clone it :
|
||||||
|
shared_ptr<AccountParams> accountParams = account->getParams()->clone();
|
||||||
|
// Then you can modify the clone :
|
||||||
|
accountParams->enableRegister(false);
|
||||||
|
// And finally setting the new Params value triggers the changes, here the logout.
|
||||||
|
account->setParams(accountParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::onRegistrationStateChanged(const shared_ptr<Account> &account, RegistrationState state, const string &message)
|
||||||
|
{
|
||||||
|
setProperty("registerText", QString::fromStdString("Your registration state is : " + message));
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
// If the Account was logged out, we clear the Core.
|
||||||
|
case RegistrationState::Cleared:
|
||||||
|
case RegistrationState::None:
|
||||||
|
mCore->clearAllAuthInfo();
|
||||||
|
mCore->clearAccounts();
|
||||||
|
logoutGuiChanges();
|
||||||
|
break;
|
||||||
|
case RegistrationState::Ok:
|
||||||
|
loginGuiChanges();
|
||||||
|
break;
|
||||||
|
case RegistrationState::Progress:
|
||||||
|
loginInProgressGuiChanges();
|
||||||
|
break;
|
||||||
|
case RegistrationState::Failed:
|
||||||
|
loginFailedGuiChanges();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::logoutGuiChanges()
|
||||||
|
{
|
||||||
|
setProperty("loginButtonEnabled", true);
|
||||||
|
setProperty("logoutButtonEnabled", false);
|
||||||
|
setProperty("loginText", "You are logged out");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::loginFailedGuiChanges()
|
||||||
|
{
|
||||||
|
setProperty("loginButtonEnabled", true);
|
||||||
|
setProperty("logoutButtonEnabled", false);
|
||||||
|
setProperty("loginText", "Login failed, try again");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::loginGuiChanges()
|
||||||
|
{
|
||||||
|
setProperty("loginButtonEnabled", false);
|
||||||
|
setProperty("logoutButtonEnabled", true);
|
||||||
|
setProperty("loginText", QString::fromStdString("You are logged in, with identity " + mCore->getIdentity() + "."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::loginInProgressGuiChanges()
|
||||||
|
{
|
||||||
|
setProperty("loginButtonEnabled", false);
|
||||||
|
setProperty("logoutButtonEnabled", false);
|
||||||
|
setProperty("loginText", QString::fromStdString("Login in progress, with identity " + mCore->getIdentity() + "."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::createLinphoneCore()
|
||||||
|
{
|
||||||
|
// Setting linphone log level to message.
|
||||||
|
auto loggingService = LoggingService::get();
|
||||||
|
loggingService->setLogLevel(LogLevel::Message);
|
||||||
|
|
||||||
|
// Configure paths.
|
||||||
|
string assetsPath = string(SDK_PATH) + "/share";
|
||||||
|
Factory::get()->setTopResourcesDir(assetsPath);
|
||||||
|
Factory::get()->setDataResourcesDir(assetsPath);
|
||||||
|
Factory::get()->setSoundResourcesDir(assetsPath + "/sounds/linphone");
|
||||||
|
Factory::get()->setRingResourcesDir(Factory::get()->getSoundResourcesDir() + "/rings");
|
||||||
|
Factory::get()->setImageResourcesDir(assetsPath + "/images");
|
||||||
|
Factory::get()->setMspluginsDir(MSPLUGINS_PATH);
|
||||||
|
|
||||||
|
// Create a core from the factory.
|
||||||
|
mCore = Factory::get()->createCore("", "", nullptr);
|
||||||
|
|
||||||
|
mCore->setRootCa(assetsPath + "/linphone/rootca.pem");
|
||||||
|
|
||||||
|
// Listen for core events.
|
||||||
|
mHandler->setListener(mCore);
|
||||||
|
|
||||||
|
// Start the core.
|
||||||
|
mCore->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::iterate()
|
||||||
|
{
|
||||||
|
if (mCore)
|
||||||
|
mCore->iterate();
|
||||||
|
}
|
||||||
60
qt/01_AccountLogin/src/CoreManager.hpp
Normal file
60
qt/01_AccountLogin/src/CoreManager.hpp
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <linphone++/linphone.hh>
|
||||||
|
|
||||||
|
class CoreHandler;
|
||||||
|
|
||||||
|
class CoreManager : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(QString loginText MEMBER mLoginText NOTIFY loginTextChanged)
|
||||||
|
Q_PROPERTY(QString registerText MEMBER mRegisterText NOTIFY registerTextChanged)
|
||||||
|
Q_PROPERTY(bool loginButtonEnabled MEMBER mLoginButtonEnabled NOTIFY loginButtonEnabledChanged)
|
||||||
|
Q_PROPERTY(bool logoutButtonEnabled MEMBER mLogoutButtonEnabled NOTIFY logoutButtonEnabledChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void init(QObject *parent);
|
||||||
|
static void uninit();
|
||||||
|
static CoreManager *getInstance();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void loginTextChanged(QString);
|
||||||
|
void registerTextChanged(QString);
|
||||||
|
void loginButtonEnabledChanged(bool);
|
||||||
|
void logoutButtonEnabledChanged(bool);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void startIterate();
|
||||||
|
void stopIterate();
|
||||||
|
void login(QString identity, QString password, QString transport);
|
||||||
|
void logout();
|
||||||
|
void onRegistrationStateChanged(const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state, const std::string &message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CoreManager(QObject *parent);
|
||||||
|
~CoreManager();
|
||||||
|
|
||||||
|
void logoutGuiChanges();
|
||||||
|
void loginFailedGuiChanges();
|
||||||
|
void loginGuiChanges();
|
||||||
|
void loginInProgressGuiChanges();
|
||||||
|
|
||||||
|
void createLinphoneCore();
|
||||||
|
void iterate();
|
||||||
|
|
||||||
|
std::shared_ptr<linphone::Core> mCore = nullptr;
|
||||||
|
QSharedPointer<CoreHandler> mHandler;
|
||||||
|
QTimer *mIterateTimer = nullptr;
|
||||||
|
|
||||||
|
QString mLoginText;
|
||||||
|
QString mRegisterText;
|
||||||
|
bool mLoginButtonEnabled = true;
|
||||||
|
bool mLogoutButtonEnabled = false;
|
||||||
|
|
||||||
|
static CoreManager *mInstance;
|
||||||
|
};
|
||||||
29
qt/01_AccountLogin/src/main.cpp
Normal file
29
qt/01_AccountLogin/src/main.cpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
#include "App.hpp"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
App app(argc, argv);
|
||||||
|
app.init();
|
||||||
|
app.exec();
|
||||||
|
app.stop();
|
||||||
|
}
|
||||||
19
qt/01_AccountLogin/ui/MainPage.qml
Normal file
19
qt/01_AccountLogin/ui/MainPage.qml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
ApplicationWindow {
|
||||||
|
id: window
|
||||||
|
visible: true
|
||||||
|
|
||||||
|
title: "Account Login"
|
||||||
|
width: 640
|
||||||
|
height: 480
|
||||||
|
|
||||||
|
// Main content
|
||||||
|
Loader {
|
||||||
|
id: contentLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
source: 'qrc:/ui/RegistrationPage.qml'
|
||||||
|
}
|
||||||
|
}
|
||||||
95
qt/01_AccountLogin/ui/RegistrationPage.qml
Normal file
95
qt/01_AccountLogin/ui/RegistrationPage.qml
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: 20
|
||||||
|
columnSpacing: 20
|
||||||
|
columns: 2
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "Identity:"
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: identityTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "sip:"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "Password:"
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: passwordTextField
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
Layout.fillWidth: true
|
||||||
|
placeholderText: "my password"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "Transport:"
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
RadioButton {
|
||||||
|
id: tlsButton
|
||||||
|
text: "TLS"
|
||||||
|
checked: true
|
||||||
|
}
|
||||||
|
RadioButton {
|
||||||
|
id: tcpButton
|
||||||
|
text: "TCP"
|
||||||
|
}
|
||||||
|
RadioButton {
|
||||||
|
id: udpButton
|
||||||
|
text: "UDP"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
spacing: 20
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: loginButton
|
||||||
|
text: "Login"
|
||||||
|
enabled: coreManager.loginButtonEnabled && identityTextField.text.length != 0 && passwordTextField.text.length != 0
|
||||||
|
onClicked: {
|
||||||
|
var transport = "tls"
|
||||||
|
if (tcpButton.checked) { transport = "tcp" }
|
||||||
|
else if (udpButton.checked) { transport = "udp" }
|
||||||
|
coreManager.login(identityTextField.text, passwordTextField.text, transport)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
id: logoutButton
|
||||||
|
text: "Logout"
|
||||||
|
enabled: coreManager.logoutButtonEnabled
|
||||||
|
onClicked: {
|
||||||
|
coreManager.logout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: loginText
|
||||||
|
text: coreManager.loginText
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
id: registrationText
|
||||||
|
text: coreManager.registerText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
qt/02_IncomingCall/.gitignore
vendored
Normal file
1
qt/02_IncomingCall/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
build/
|
||||||
52
qt/02_IncomingCall/CMakeLists.txt
Normal file
52
qt/02_IncomingCall/CMakeLists.txt
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.22)
|
||||||
|
|
||||||
|
project(02_IncomingCall LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
find_package(Qt5 REQUIRED COMPONENTS Core Gui Qml Quick)
|
||||||
|
find_package(LinphoneCxx REQUIRED)
|
||||||
|
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
SET(CMAKE_AUTOUIC ON)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
"src/main.cpp"
|
||||||
|
"src/App.cpp"
|
||||||
|
"src/CoreHandler.cpp"
|
||||||
|
"src/CoreListener.cpp"
|
||||||
|
"src/CoreManager.cpp"
|
||||||
|
)
|
||||||
|
set(QRC_RESOURCES resources.qrc)
|
||||||
|
set(QML_SOURCES)
|
||||||
|
file(STRINGS ${QRC_RESOURCES} QRC_RESOURCES_CONTENT)
|
||||||
|
foreach(line ${QRC_RESOURCES_CONTENT})
|
||||||
|
set(result)
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"^[ \t]*<[ \t]*file[ \t]*>[ \t]*(.+\\.[a-z]+)[ \t]*<[ \t]*/[ \t]*file[ \t]*>[ \t]*$"
|
||||||
|
"\\1"
|
||||||
|
result
|
||||||
|
"${line}"
|
||||||
|
)
|
||||||
|
string(REGEX MATCH "\\.[a-z]+$" is_ui ${result})
|
||||||
|
if(NOT ${is_ui} STREQUAL "")
|
||||||
|
list(APPEND QML_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/${result}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
get_filename_component(SDK_PATH "${CMAKE_PREFIX_PATH}" REALPATH)
|
||||||
|
find_path(MSPLUGINS_PATH "plugins" PATH_SUFFIXES "lib/mediastreamer" "lib64/mediastreamer" REQUIRED)
|
||||||
|
set(MSPLUGINS_PATH "${MSPLUGINS_PATH}/plugins")
|
||||||
|
|
||||||
|
add_executable(02_IncomingCall ${SOURCES} ${QML_SOURCES} ${QRC_RESOURCES})
|
||||||
|
|
||||||
|
target_compile_definitions(02_IncomingCall PRIVATE "SDK_PATH=\"${SDK_PATH}\"" "MSPLUGINS_PATH=\"${MSPLUGINS_PATH}\"")
|
||||||
|
target_include_directories(02_IncomingCall PRIVATE ${LINPHONECXX_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(02_IncomingCall PRIVATE Qt5::Core Qt5::Gui Qt5::Qml Qt5::Quick ${LINPHONECXX_LIBRARIES})
|
||||||
|
|
||||||
|
set_target_properties(02_IncomingCall PROPERTIES AUTORCC ON)
|
||||||
|
set_target_properties(02_IncomingCall PROPERTIES
|
||||||
|
WIN32_EXECUTABLE ON
|
||||||
|
MACOSX_BUNDLE ON
|
||||||
|
)
|
||||||
15
qt/02_IncomingCall/README.md
Normal file
15
qt/02_IncomingCall/README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Incoming call tutorial
|
||||||
|
|
||||||
|
This time we are going to receive our first calls!
|
||||||
|
|
||||||
|
If you don't have SIP friends to test with, you can also install Linphone on your mobile device (Android or iOS) and call yourself with a different account.
|
||||||
|
|
||||||
|
|
||||||
|
## How to build
|
||||||
|
|
||||||
|
In the following instructions, replace **<PATH-TO-SDK>** by the real path where your SDK is located, e.g. *~/projects/linphone-sdk/build-default/linphone-sdk/desktop/*
|
||||||
|
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DCMAKE_PREFIX_PATH=<PATH-TO-SDK>
|
||||||
|
cmake --build .
|
||||||
7
qt/02_IncomingCall/resources.qrc
Normal file
7
qt/02_IncomingCall/resources.qrc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>ui/MainPage.qml</file>
|
||||||
|
<file>ui/CallPage.qml</file>
|
||||||
|
<file>ui/RegistrationPage.qml</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
49
qt/02_IncomingCall/src/App.cpp
Normal file
49
qt/02_IncomingCall/src/App.cpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#include <QDir>
|
||||||
|
#include <QQmlContext>
|
||||||
|
|
||||||
|
#include "App.hpp"
|
||||||
|
#include "CoreManager.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace linphone;
|
||||||
|
|
||||||
|
App::App(int &argc, char *argv[]) : QGuiApplication(argc, argv)
|
||||||
|
{
|
||||||
|
setOrganizationName("Belledonne Communications");
|
||||||
|
setOrganizationDomain("belledonne-communications.com");
|
||||||
|
setApplicationName(QFileInfo(applicationFilePath()).baseName());
|
||||||
|
}
|
||||||
|
|
||||||
|
App::~App()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::init()
|
||||||
|
{
|
||||||
|
registerTypes();
|
||||||
|
|
||||||
|
mEngine = new QQmlApplicationEngine();
|
||||||
|
mEngine->load(QUrl("qrc:/ui/MainPage.qml"));
|
||||||
|
if (mEngine->rootObjects().isEmpty())
|
||||||
|
qFatal("Unable to open main window.");
|
||||||
|
|
||||||
|
// Initialize the CoreManager singleton and add it to the Qml context.
|
||||||
|
CoreManager::init(this);
|
||||||
|
auto coreManager = CoreManager::getInstance();
|
||||||
|
QQmlContext *ctx = mEngine->rootContext();
|
||||||
|
ctx->setContextProperty("coreManager", coreManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::stop()
|
||||||
|
{
|
||||||
|
CoreManager::uninit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::registerTypes()
|
||||||
|
{
|
||||||
|
qRegisterMetaType<string>();
|
||||||
|
qRegisterMetaType<RegistrationState>();
|
||||||
|
qRegisterMetaType<shared_ptr<Account>>();
|
||||||
|
qRegisterMetaType<Call::State>();
|
||||||
|
qRegisterMetaType<shared_ptr<Call>>();
|
||||||
|
}
|
||||||
27
qt/02_IncomingCall/src/App.hpp
Normal file
27
qt/02_IncomingCall/src/App.hpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QQmlApplicationEngine>
|
||||||
|
|
||||||
|
#include <linphone++/linphone.hh>
|
||||||
|
|
||||||
|
class App : public QGuiApplication
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
App(int &argc, char *argv[]);
|
||||||
|
~App();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void registerTypes();
|
||||||
|
|
||||||
|
QQmlApplicationEngine *mEngine = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(std::string);
|
||||||
|
Q_DECLARE_METATYPE(linphone::RegistrationState);
|
||||||
|
Q_DECLARE_METATYPE(std::shared_ptr<linphone::Account>);
|
||||||
|
Q_DECLARE_METATYPE(linphone::Call::State);
|
||||||
|
Q_DECLARE_METATYPE(std::shared_ptr<linphone::Call>);
|
||||||
75
qt/02_IncomingCall/src/CoreHandler.cpp
Normal file
75
qt/02_IncomingCall/src/CoreHandler.cpp
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "CoreHandler.hpp"
|
||||||
|
#include "CoreListener.hpp"
|
||||||
|
#include "CoreManager.hpp"
|
||||||
|
|
||||||
|
CoreHandler::CoreHandler()
|
||||||
|
{
|
||||||
|
mCoreListener = std::make_shared<CoreListener>();
|
||||||
|
connectTo(mCoreListener.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreHandler::setListener(std::shared_ptr<linphone::Core> core)
|
||||||
|
{
|
||||||
|
core->addListener(mCoreListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreHandler::removeListener(std::shared_ptr<linphone::Core> core)
|
||||||
|
{
|
||||||
|
core->removeListener(mCoreListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreHandler::onAccountRegistrationStateChanged(const std::shared_ptr<linphone::Core> &, const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state, const std::string &message)
|
||||||
|
{
|
||||||
|
emit registrationStateChanged(account, state, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreHandler::onCallStateStateChanged(const std::shared_ptr<linphone::Core> &, const std::shared_ptr<linphone::Call> &call, linphone::Call::State state, const std::string &message)
|
||||||
|
{
|
||||||
|
emit callStateChanged(call, state, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreHandler::onGlobalStateChanged(const std::shared_ptr<linphone::Core> &, linphone::GlobalState state, const std::string &message)
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case linphone::GlobalState::On:
|
||||||
|
qInfo() << "Core is running " << QString::fromStdString(message);
|
||||||
|
break;
|
||||||
|
case linphone::GlobalState::Off:
|
||||||
|
qInfo() << "Core is stopped " << QString::fromStdString(message);
|
||||||
|
emit coreStopped();
|
||||||
|
break;
|
||||||
|
case linphone::GlobalState::Startup:
|
||||||
|
qInfo() << "Core is starting" << QString::fromStdString(message);
|
||||||
|
emit coreStarting();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreHandler::connectTo(CoreListener *listener)
|
||||||
|
{
|
||||||
|
connect(listener, &CoreListener::accountRegistrationStateChanged, this, &CoreHandler::onAccountRegistrationStateChanged);
|
||||||
|
connect(listener, &CoreListener::callStateChanged, this, &CoreHandler::onCallStateStateChanged);
|
||||||
|
connect(listener, &CoreListener::globalStateChanged, this, &CoreHandler::onGlobalStateChanged);
|
||||||
|
}
|
||||||
49
qt/02_IncomingCall/src/CoreHandler.hpp
Normal file
49
qt/02_IncomingCall/src/CoreHandler.hpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <linphone++/linphone.hh>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class CoreListener;
|
||||||
|
|
||||||
|
class CoreHandler : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
CoreHandler();
|
||||||
|
|
||||||
|
void setListener(std::shared_ptr<linphone::Core> core);
|
||||||
|
void removeListener(std::shared_ptr<linphone::Core> core);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void coreStarting();
|
||||||
|
void coreStopped();
|
||||||
|
void callStateChanged(const std::shared_ptr<linphone::Call>, linphone::Call::State state, const std::string &message);
|
||||||
|
void registrationStateChanged(const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state, const std::string &message);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onAccountRegistrationStateChanged(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state, const std::string &message);
|
||||||
|
void onCallStateStateChanged(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Call> &call, linphone::Call::State state, const std::string &message);
|
||||||
|
void onGlobalStateChanged(const std::shared_ptr<linphone::Core> &core, linphone::GlobalState gstate, const std::string &message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void connectTo(CoreListener *listener);
|
||||||
|
std::shared_ptr<CoreListener> mCoreListener;
|
||||||
|
};
|
||||||
37
qt/02_IncomingCall/src/CoreListener.cpp
Normal file
37
qt/02_IncomingCall/src/CoreListener.cpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CoreListener.hpp"
|
||||||
|
|
||||||
|
CoreListener::CoreListener(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreListener::onAccountRegistrationStateChanged(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state, const std::string &message)
|
||||||
|
{
|
||||||
|
emit accountRegistrationStateChanged(core, account, state, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreListener::onCallStateChanged(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Call> &call, linphone::Call::State state, const std::string &message)
|
||||||
|
{
|
||||||
|
emit callStateChanged(core, call, state, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreListener::onGlobalStateChanged(const std::shared_ptr<linphone::Core> &core, linphone::GlobalState gstate, const std::string &message)
|
||||||
|
{
|
||||||
|
emit globalStateChanged(core, gstate, message);
|
||||||
|
}
|
||||||
39
qt/02_IncomingCall/src/CoreListener.hpp
Normal file
39
qt/02_IncomingCall/src/CoreListener.hpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <linphone++/linphone.hh>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class CoreListener : public QObject, public linphone::CoreListener
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
CoreListener(QObject *parent = nullptr);
|
||||||
|
virtual ~CoreListener() = default;
|
||||||
|
|
||||||
|
virtual void onAccountRegistrationStateChanged(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state, const std::string &message) override;
|
||||||
|
virtual void onCallStateChanged(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Call> &call, linphone::Call::State state, const std::string &message) override;
|
||||||
|
virtual void onGlobalStateChanged(const std::shared_ptr<linphone::Core> &core, linphone::GlobalState gstate, const std::string &message) override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void accountRegistrationStateChanged(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state, const std::string &message);
|
||||||
|
void callStateChanged(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Call> &call, linphone::Call::State state, const std::string &message);
|
||||||
|
void globalStateChanged(const std::shared_ptr<linphone::Core> &core, linphone::GlobalState gstate, const std::string &message);
|
||||||
|
};
|
||||||
285
qt/02_IncomingCall/src/CoreManager.cpp
Normal file
285
qt/02_IncomingCall/src/CoreManager.cpp
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "CoreHandler.hpp"
|
||||||
|
#include "CoreManager.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace linphone;
|
||||||
|
|
||||||
|
CoreManager *CoreManager::mInstance = nullptr;
|
||||||
|
|
||||||
|
CoreManager::CoreManager(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
mPage = QString("qrc:/ui/RegistrationPage.qml");
|
||||||
|
mHeaderText = QString("Registration Form");
|
||||||
|
mSoundButtonText = QString("Switch off sound");
|
||||||
|
mMicrophoneButtonText = QString("Mute");
|
||||||
|
mHandler = QSharedPointer<CoreHandler>::create();
|
||||||
|
CoreHandler *coreHandler = mHandler.get();
|
||||||
|
QObject::connect(coreHandler, &CoreHandler::coreStarting, this, &CoreManager::startIterate, Qt::QueuedConnection);
|
||||||
|
QObject::connect(coreHandler, &CoreHandler::coreStopped, this, &CoreManager::stopIterate, Qt::QueuedConnection);
|
||||||
|
QObject::connect(coreHandler, &CoreHandler::callStateChanged, this, &CoreManager::onCallStateChanged, Qt::QueuedConnection);
|
||||||
|
QObject::connect(coreHandler, &CoreHandler::registrationStateChanged, this, &CoreManager::onRegistrationStateChanged, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
// Delay the creation of the core so that the CoreManager instance is
|
||||||
|
// already set.
|
||||||
|
QTimer::singleShot(10, [this]()
|
||||||
|
{ createLinphoneCore(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreManager::~CoreManager()
|
||||||
|
{
|
||||||
|
mHandler->removeListener(mCore);
|
||||||
|
mHandler = nullptr;
|
||||||
|
mCore = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::init(QObject *parent)
|
||||||
|
{
|
||||||
|
if (mInstance)
|
||||||
|
return;
|
||||||
|
mInstance = new CoreManager(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::uninit()
|
||||||
|
{
|
||||||
|
if (mInstance)
|
||||||
|
{
|
||||||
|
mInstance->stopIterate();
|
||||||
|
auto core = mInstance->mCore;
|
||||||
|
delete mInstance;
|
||||||
|
mInstance = nullptr;
|
||||||
|
core->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreManager *CoreManager::getInstance()
|
||||||
|
{
|
||||||
|
return mInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::startIterate()
|
||||||
|
{
|
||||||
|
// Start a timer to call the core iterate every 20 ms.
|
||||||
|
mIterateTimer = new QTimer(this);
|
||||||
|
mIterateTimer->setInterval(20);
|
||||||
|
QObject::connect(mIterateTimer, &QTimer::timeout, this, &CoreManager::iterate);
|
||||||
|
qInfo() << QStringLiteral("Start iterate");
|
||||||
|
mIterateTimer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::stopIterate()
|
||||||
|
{
|
||||||
|
qInfo() << QStringLiteral("Stop iterate");
|
||||||
|
mIterateTimer->stop();
|
||||||
|
mIterateTimer->deleteLater(); // Allow the timer to continue its stuff
|
||||||
|
mIterateTimer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::login(QString identity, QString password)
|
||||||
|
{
|
||||||
|
if (mLoginButtonEnabled)
|
||||||
|
{
|
||||||
|
setProperty("loginButtonEnabled", false);
|
||||||
|
|
||||||
|
shared_ptr<Address> address = Factory::get()->createAddress(identity.toStdString());
|
||||||
|
shared_ptr<AuthInfo> authInfo = Factory::get()->createAuthInfo(address->getUsername(), "", password.toStdString(), "", "", address->getDomain());
|
||||||
|
mCore->addAuthInfo(authInfo);
|
||||||
|
|
||||||
|
shared_ptr<AccountParams> accountParams = mCore->createAccountParams();
|
||||||
|
accountParams->setIdentityAddress(address);
|
||||||
|
string serverAddr = "sip:" + address->getDomain() + ";transport=tls";
|
||||||
|
accountParams->setServerAddr(serverAddr);
|
||||||
|
|
||||||
|
accountParams->enableRegister(true);
|
||||||
|
|
||||||
|
shared_ptr<Account> account = mCore->createAccount(accountParams);
|
||||||
|
mCore->addAccount(account);
|
||||||
|
mCore->setDefaultAccount(account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::logout()
|
||||||
|
{
|
||||||
|
shared_ptr<Account> account = mCore->getDefaultAccount();
|
||||||
|
if (account)
|
||||||
|
{
|
||||||
|
shared_ptr<AccountParams> accountParams = account->getParams()->clone();
|
||||||
|
accountParams->enableRegister(false);
|
||||||
|
account->setParams(accountParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::onCallStateChanged(const std::shared_ptr<linphone::Call> &call, linphone::Call::State state, const std::string &message)
|
||||||
|
{
|
||||||
|
setProperty("callStateText", QString::fromStdString("Your call state is: " + message));
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case Call::State::IncomingReceived:
|
||||||
|
// When you receive a call the Call::State is incoming receive. By default you can only have one current call,
|
||||||
|
// so if a call is in progress or one is already ringing the second remote call will be decline with the reason
|
||||||
|
// "Busy". If you want to implement a multi call app you can increase Core::setMaxCalls.
|
||||||
|
// Here we store the incoming call reference so we can accept or decline the call on user input.
|
||||||
|
mIncomingCall = call;
|
||||||
|
// And we update the GUI to notify the user of the incoming call.
|
||||||
|
setProperty("incomingCallVisible", true);
|
||||||
|
setProperty("incomingCallText", QString::fromStdString(mIncomingCall->getRemoteAddress()->asString()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Call::State::StreamsRunning:
|
||||||
|
// The StreamsRunning state is the default one during a call.
|
||||||
|
callInProgressGuiUpdates();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Call::State::Error:
|
||||||
|
case Call::State::End:
|
||||||
|
case Call::State::Released:
|
||||||
|
// By default after 30 seconds of ringing without accept or decline a call is
|
||||||
|
// automatically ended.
|
||||||
|
mIncomingCall = nullptr;
|
||||||
|
endingCallGuiUpdates();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::onRegistrationStateChanged(const shared_ptr<Account> &account, RegistrationState state, const string &message)
|
||||||
|
{
|
||||||
|
setProperty("registerText", QString::fromStdString("Your registration state is : " + message));
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
// If the Account was logged out, we clear the Core.
|
||||||
|
case RegistrationState::Cleared:
|
||||||
|
case RegistrationState::None:
|
||||||
|
mCore->clearAllAuthInfo();
|
||||||
|
mCore->clearAccounts();
|
||||||
|
setProperty("loginButtonEnabled", true);
|
||||||
|
break;
|
||||||
|
case RegistrationState::Ok:
|
||||||
|
setProperty("loginButtonEnabled", false);
|
||||||
|
setProperty("headerText", QString::fromStdString("Hello " + mCore->getDefaultProxyConfig()->findAuthInfo()->getUsername()));
|
||||||
|
setProperty("page", QString("qrc:/ui/CallPage.qml"));
|
||||||
|
break;
|
||||||
|
case RegistrationState::Progress:
|
||||||
|
setProperty("loginButtonEnabled", false);
|
||||||
|
break;
|
||||||
|
case RegistrationState::Failed:
|
||||||
|
setProperty("loginButtonEnabled", true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::hangup()
|
||||||
|
{
|
||||||
|
// Simply call terminateAllCalls to hang out.
|
||||||
|
mCore->terminateAllCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::soundButtonClicked()
|
||||||
|
{
|
||||||
|
if (toggleSpeaker())
|
||||||
|
{
|
||||||
|
setProperty("soundButtonText", QString("Switch on Sound"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setProperty("soundButtonText", QString("Switch off Sound"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::microphoneButtonClicked()
|
||||||
|
{
|
||||||
|
if (toggleMicrophone())
|
||||||
|
{
|
||||||
|
setProperty("microphoneButtonText", QString("Mute"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setProperty("microphoneButtonText", QString("Unmute"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::answer()
|
||||||
|
{
|
||||||
|
if (mIncomingCall)
|
||||||
|
{
|
||||||
|
// To accept a call only use the accept() method on the call object.
|
||||||
|
// If we wanted, we could create a CallParams object and answer using this object to make changes to the call configuration.
|
||||||
|
mIncomingCall->accept();
|
||||||
|
mIncomingCall = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::decline()
|
||||||
|
{
|
||||||
|
if (mIncomingCall)
|
||||||
|
{
|
||||||
|
// You have to give a Reason to decline a call. This info is sent to the remote.
|
||||||
|
mIncomingCall->decline(Reason::Declined);
|
||||||
|
mIncomingCall = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::createLinphoneCore()
|
||||||
|
{
|
||||||
|
// Setting linphone log level to message.
|
||||||
|
auto loggingService = LoggingService::get();
|
||||||
|
loggingService->setLogLevel(LogLevel::Message);
|
||||||
|
|
||||||
|
// Configure paths.
|
||||||
|
string assetsPath = string(SDK_PATH) + "/share";
|
||||||
|
Factory::get()->setTopResourcesDir(assetsPath);
|
||||||
|
Factory::get()->setDataResourcesDir(assetsPath);
|
||||||
|
Factory::get()->setSoundResourcesDir(assetsPath + "/sounds/linphone");
|
||||||
|
Factory::get()->setRingResourcesDir(Factory::get()->getSoundResourcesDir() + "/rings");
|
||||||
|
Factory::get()->setImageResourcesDir(assetsPath + "/images");
|
||||||
|
Factory::get()->setMspluginsDir(MSPLUGINS_PATH);
|
||||||
|
|
||||||
|
// Create a core from the factory.
|
||||||
|
mCore = Factory::get()->createCore("", "", nullptr);
|
||||||
|
|
||||||
|
mCore->setRootCa(assetsPath + "/linphone/rootca.pem");
|
||||||
|
|
||||||
|
// Listen for core events.
|
||||||
|
mHandler->setListener(mCore);
|
||||||
|
|
||||||
|
// Start the core.
|
||||||
|
mCore->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::iterate()
|
||||||
|
{
|
||||||
|
if (mCore)
|
||||||
|
mCore->iterate();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CoreManager::toggleSpeaker()
|
||||||
|
{
|
||||||
|
// Calling setSpeakerMuted(true) on a Call object disables the sound output of this call.
|
||||||
|
bool newValue = !mCore->getCurrentCall()->getSpeakerMuted();
|
||||||
|
mCore->getCurrentCall()->setSpeakerMuted(newValue);
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CoreManager::toggleMicrophone()
|
||||||
|
{
|
||||||
|
// The following toggles the microphone, disabling completely / enabling the sound capture from the device microphone
|
||||||
|
bool newValue = !mCore->micEnabled();
|
||||||
|
mCore->enableMic(newValue);
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::callInProgressGuiUpdates()
|
||||||
|
{
|
||||||
|
setProperty("incomingCallVisible", false);
|
||||||
|
setProperty("inCallButtonsEnabled", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoreManager::endingCallGuiUpdates()
|
||||||
|
{
|
||||||
|
setProperty("incomingCallVisible", false);
|
||||||
|
setProperty("inCallButtonsEnabled", false);
|
||||||
|
setProperty("soundButtonText", "Switch off Sound");
|
||||||
|
setProperty("microphoneButtonText", "Mute");
|
||||||
|
}
|
||||||
84
qt/02_IncomingCall/src/CoreManager.hpp
Normal file
84
qt/02_IncomingCall/src/CoreManager.hpp
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <linphone++/linphone.hh>
|
||||||
|
|
||||||
|
class CoreHandler;
|
||||||
|
|
||||||
|
class CoreManager : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(QString page MEMBER mPage NOTIFY pageChanged);
|
||||||
|
Q_PROPERTY(QString headerText MEMBER mHeaderText NOTIFY headerTextChanged)
|
||||||
|
Q_PROPERTY(QString registerText MEMBER mRegisterText NOTIFY registerTextChanged)
|
||||||
|
Q_PROPERTY(bool loginButtonEnabled MEMBER mLoginButtonEnabled NOTIFY loginButtonEnabledChanged)
|
||||||
|
Q_PROPERTY(QString callStateText MEMBER mCallStateText NOTIFY callStateTextChanged)
|
||||||
|
Q_PROPERTY(bool incomingCallVisible MEMBER mIncomingCallVisible NOTIFY incomingCallVisibleChanged)
|
||||||
|
Q_PROPERTY(QString incomingCallText MEMBER mIncomingCallText NOTIFY incomingCallTextChanged)
|
||||||
|
Q_PROPERTY(bool inCallButtonsEnabled MEMBER mInCallButtonsEnabled NOTIFY inCallButtonsEnabledChanged)
|
||||||
|
Q_PROPERTY(QString soundButtonText MEMBER mSoundButtonText NOTIFY soundButtonTextChanged)
|
||||||
|
Q_PROPERTY(QString microphoneButtonText MEMBER mMicrophoneButtonText NOTIFY microphoneButtonTextChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void init(QObject *parent);
|
||||||
|
static void uninit();
|
||||||
|
static CoreManager *getInstance();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void pageChanged(QString);
|
||||||
|
void headerTextChanged(QString);
|
||||||
|
void registerTextChanged(QString);
|
||||||
|
void loginButtonEnabledChanged(bool);
|
||||||
|
void callStateTextChanged(QString);
|
||||||
|
void incomingCallVisibleChanged(bool);
|
||||||
|
void incomingCallTextChanged(QString);
|
||||||
|
void inCallButtonsEnabledChanged(bool);
|
||||||
|
void soundButtonTextChanged(QString);
|
||||||
|
void microphoneButtonTextChanged(QString);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void startIterate();
|
||||||
|
void stopIterate();
|
||||||
|
void login(QString identity, QString password);
|
||||||
|
void logout();
|
||||||
|
void onCallStateChanged(const std::shared_ptr<linphone::Call> &call, linphone::Call::State state, const std::string &message);
|
||||||
|
void onRegistrationStateChanged(const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state, const std::string &message);
|
||||||
|
void hangup();
|
||||||
|
void soundButtonClicked();
|
||||||
|
void microphoneButtonClicked();
|
||||||
|
void answer();
|
||||||
|
void decline();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CoreManager(QObject *parent);
|
||||||
|
~CoreManager();
|
||||||
|
|
||||||
|
void createLinphoneCore();
|
||||||
|
void iterate();
|
||||||
|
bool toggleSpeaker();
|
||||||
|
bool toggleMicrophone();
|
||||||
|
void callInProgressGuiUpdates();
|
||||||
|
void endingCallGuiUpdates();
|
||||||
|
|
||||||
|
std::shared_ptr<linphone::Core> mCore = nullptr;
|
||||||
|
std::shared_ptr<linphone::Call> mIncomingCall = nullptr;
|
||||||
|
QSharedPointer<CoreHandler> mHandler;
|
||||||
|
QTimer *mIterateTimer = nullptr;
|
||||||
|
|
||||||
|
QString mPage;
|
||||||
|
QString mHeaderText;
|
||||||
|
QString mRegisterText;
|
||||||
|
bool mLoginButtonEnabled = true;
|
||||||
|
QString mCallStateText;
|
||||||
|
bool mIncomingCallVisible = false;
|
||||||
|
QString mIncomingCallText;
|
||||||
|
bool mInCallButtonsEnabled = false;
|
||||||
|
QString mSoundButtonText;
|
||||||
|
QString mMicrophoneButtonText;
|
||||||
|
|
||||||
|
static CoreManager *mInstance;
|
||||||
|
};
|
||||||
29
qt/02_IncomingCall/src/main.cpp
Normal file
29
qt/02_IncomingCall/src/main.cpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
#include "App.hpp"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
App app(argc, argv);
|
||||||
|
app.init();
|
||||||
|
app.exec();
|
||||||
|
app.stop();
|
||||||
|
}
|
||||||
77
qt/02_IncomingCall/ui/CallPage.qml
Normal file
77
qt/02_IncomingCall/ui/CallPage.qml
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
columns: 1
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: coreManager.callStateText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
spacing: 20
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Hang up"
|
||||||
|
enabled: coreManager.inCallButtonsEnabled
|
||||||
|
onClicked: {
|
||||||
|
coreManager.hangup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: coreManager.soundButtonText
|
||||||
|
enabled: coreManager.inCallButtonsEnabled
|
||||||
|
onClicked: {
|
||||||
|
coreManager.soundButtonClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: coreManager.microphoneButtonText
|
||||||
|
enabled: coreManager.inCallButtonsEnabled
|
||||||
|
onClicked: {
|
||||||
|
coreManager.microphoneButtonClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.margins: 20
|
||||||
|
columnSpacing: 20
|
||||||
|
columns: 2
|
||||||
|
visible: coreManager.incomingCallVisible
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
text: "You have a call from: " + coreManager.incomingCallText
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Answer"
|
||||||
|
onClicked: {
|
||||||
|
coreManager.answer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: "Decline"
|
||||||
|
onClicked: {
|
||||||
|
coreManager.decline()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
qt/02_IncomingCall/ui/MainPage.qml
Normal file
35
qt/02_IncomingCall/ui/MainPage.qml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
ApplicationWindow {
|
||||||
|
id: window
|
||||||
|
visible: true
|
||||||
|
|
||||||
|
title: "Account Login"
|
||||||
|
width: 640
|
||||||
|
height: 480
|
||||||
|
|
||||||
|
header: Rectangle {
|
||||||
|
color: "lightgray";
|
||||||
|
height: 40;
|
||||||
|
width: window.width
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: coreManager.headerText
|
||||||
|
font.bold: true
|
||||||
|
font.capitalization: Font.AllUppercase
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main content
|
||||||
|
Loader {
|
||||||
|
id: contentLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
source: coreManager.page
|
||||||
|
}
|
||||||
|
}
|
||||||
57
qt/02_IncomingCall/ui/RegistrationPage.qml
Normal file
57
qt/02_IncomingCall/ui/RegistrationPage.qml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
//Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.margins: 20
|
||||||
|
columnSpacing: 20
|
||||||
|
columns: 2
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "Identity:"
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: identityTextField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "sip:"
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "Password:"
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: passwordTextField
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
Layout.fillWidth: true
|
||||||
|
placeholderText: "my password"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Login"
|
||||||
|
enabled: coreManager.loginButtonEnabled && identityTextField.text.length !== 0 && passwordTextField.text.length !== 0
|
||||||
|
onClicked: {
|
||||||
|
coreManager.login(identityTextField.text, passwordTextField.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: coreManager.registerText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user