Fix crash on logger (instance lost).

Add Call model.
Start audio call from Utils.
Simplify VariantObject to use only setValue().
Add notifications.
This commit is contained in:
Julien Wadel 2023-11-10 16:41:41 +01:00
parent 62a9d34e09
commit 7ff6989614
34 changed files with 1883 additions and 380 deletions

View file

@ -35,6 +35,9 @@ if(NOT WIN32)
add_compile_options(-Werror=deprecated-declarations)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG -DQT_NO_DEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DQT_QML_DEBUG -DQT_DECLARATIVE_DEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG -DQT_QML_DEBUG -DQT_DECLARATIVE_DEBUG" )
set(CMAKE_INCLUDE_CURRENT_DIR ON)#useful for config.h
include(application_info.cmake)

View file

@ -23,13 +23,18 @@
#include "App.hpp"
#include <QCoreApplication>
#include <QFileSelector>
#include <QGuiApplication>
#include <QLibraryInfo>
#include <QQmlContext>
#include <QQmlFileSelector>
#include <QTimer>
#include "core/account/Account.hpp"
#include "core/account/AccountProxy.hpp"
#include "core/logger/QtLogger.hpp"
#include "core/login/LoginPage.hpp"
#include "core/notifier/Notifier.hpp"
#include "core/phone-number/PhoneNumber.hpp"
#include "core/phone-number/PhoneNumberProxy.hpp"
#include "core/singleapplication/singleapplication.h"
@ -50,6 +55,9 @@ App *App::getInstance() {
return dynamic_cast<App *>(QApplication::instance());
}
Notifier *App::getNotifier() const {
return mNotifier;
}
//-----------------------------------------------------------
// Initializations
//-----------------------------------------------------------
@ -76,11 +84,22 @@ void App::init() {
// QML
mEngine = new QQmlApplicationEngine(this);
// Provide `+custom` folders for custom components and `5.9` for old components.
QStringList selectors("custom");
const QVersionNumber &version = QLibraryInfo::version();
if (version.majorVersion() == 5 && version.minorVersion() == 9) selectors.push_back("5.9");
auto selector = new QQmlFileSelector(mEngine, mEngine);
selector->setExtraSelectors(selectors);
qInfo() << QStringLiteral("[App] Activated selectors:") << selector->selector()->allSelectors();
mEngine->addImportPath(":/");
mEngine->rootContext()->setContextProperty("applicationDirPath", QGuiApplication::applicationDirPath());
initCppInterfaces();
mEngine->addImageProvider(ImageProvider::ProviderId, new ImageProvider());
// Enable notifications.
mNotifier = new Notifier(mEngine);
const QUrl url(u"qrc:/Linphone/view/App/Main.qml"_qs);
QObject::connect(
mEngine, &QQmlApplicationEngine::objectCreated, this,
@ -110,6 +129,7 @@ void App::initCppInterfaces() {
qmlRegisterUncreatableType<PhoneNumber>(Constants::MainQmlUri, 1, 0, "PhoneNumber", QLatin1String("Uncreatable"));
qmlRegisterType<AccountProxy>(Constants::MainQmlUri, 1, 0, "AccountProxy");
qmlRegisterUncreatableType<Account>(Constants::MainQmlUri, 1, 0, "Account", QLatin1String("Uncreatable"));
qmlRegisterUncreatableType<Call>(Constants::MainQmlUri, 1, 0, "Call", QLatin1String("Uncreatable"));
LinphoneEnums::registerMetaTypes();
}

View file

@ -26,11 +26,13 @@
#include "model/core/CoreModel.hpp"
class Thread;
class Notifier;
class App : public SingleApplication {
public:
App(int &argc, char *argv[]);
static App *getInstance();
Notifier *getNotifier() const;
// App::postModelAsync(<lambda>) => run lambda in model thread and continue.
// App::postModelSync(<lambda>) => run lambda in current thread and block connection.
@ -43,6 +45,14 @@ public:
QMetaObject::invokeMethod(CoreModel::getInstance().get(), callable);
}
template <typename Func, typename... Args>
static auto postCoreAsync(Func &&callable, Args &&...args) {
QMetaObject::invokeMethod(App::getInstance(), callable, args...);
}
template <typename Func>
static auto postCoreAsync(Func &&callable) {
QMetaObject::invokeMethod(App::getInstance(), callable);
}
template <typename Func, typename... Args>
static auto postModelSync(Func &&callable, Args &&...args) {
if (QThread::currentThread() != CoreModel::getInstance()->thread()) {
bool end = false;
@ -70,4 +80,5 @@ private:
QCommandLineParser *mParser = nullptr;
Thread *mLinphoneThread = nullptr;
Notifier *mNotifier = nullptr;
};

View file

@ -3,8 +3,10 @@ list(APPEND _LINPHONEAPP_SOURCES
core/account/AccountList.cpp
core/account/AccountProxy.cpp
core/App.cpp
core/call/Call.cpp
core/logger/QtLogger.cpp
core/login/LoginPage.cpp
core/notifier/Notifier.cpp
core/path/Paths.cpp
core/phone-number/PhoneNumber.cpp
core/phone-number/PhoneNumberList.cpp

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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 "Call.hpp"
#include "core/App.hpp"
#include "tool/Utils.hpp"
DEFINE_ABSTRACT_OBJECT(Call)
Call::Call(const std::shared_ptr<linphone::Call> &call) : QObject(nullptr) {
// Should be call from model Thread
mustBeInLinphoneThread(getClassName());
mCallModel = Utils::makeQObject_ptr<CallModel>(call);
connect(mCallModel.get(), &CallModel::stateChanged, this, &Call::onStateChanged);
connect(this, &Call::lAccept, mCallModel.get(), &CallModel::accept);
connect(this, &Call::lDecline, mCallModel.get(), &CallModel::decline);
connect(this, &Call::lTerminate, mCallModel.get(), &CallModel::terminate);
mCallModel->setSelf(mCallModel);
mState = LinphoneEnums::fromLinphone(call->getState());
}
Call::~Call() {
mustBeInMainThread("~" + getClassName());
emit mCallModel->removeListener();
}
LinphoneEnums::CallStatus Call::getStatus() const {
return mStatus;
}
void Call::setStatus(LinphoneEnums::CallStatus status) {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
if (mStatus != status) {
mStatus = status;
emit statusChanged(mStatus);
}
}
LinphoneEnums::CallState Call::getState() const {
return mState;
}
void Call::setState(LinphoneEnums::CallState state, const QString &message) {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
if (mState != state) {
mState = state;
if (state == LinphoneEnums::CallState::Error) setLastErrorMessage(message);
emit stateChanged(mState);
}
}
void Call::onStateChanged(linphone::Call::State state, const std::string &message) {
setState(LinphoneEnums::fromLinphone(state), Utils::coreStringToAppString(message));
}
QString Call::getLastErrorMessage() const {
return mLastErrorMessage;
}
void Call::setLastErrorMessage(const QString &message) {
if (mLastErrorMessage != message) {
mLastErrorMessage = message;
emit lastErrorMessageChanged();
}
}

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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/>.
*/
#ifndef CALL_H_
#define CALL_H_
#include "model/call/CallModel.hpp"
#include "tool/LinphoneEnums.hpp"
#include <QObject>
#include <QSharedPointer>
#include <linphone++/linphone.hh>
class Call : public QObject, public AbstractObject {
Q_OBJECT
Q_PROPERTY(LinphoneEnums::CallStatus status READ getStatus NOTIFY statusChanged)
Q_PROPERTY(LinphoneEnums::CallState state READ getState NOTIFY stateChanged)
Q_PROPERTY(QString lastErrorMessage READ getLastErrorMessage NOTIFY lastErrorMessageChanged)
public:
// Should be call from model Thread. Will be automatically in App thread after initialization
Call(const std::shared_ptr<linphone::Call> &call);
~Call();
LinphoneEnums::CallStatus getStatus() const;
void setStatus(LinphoneEnums::CallStatus status);
LinphoneEnums::CallState getState() const;
void setState(LinphoneEnums::CallState state, const QString &message);
void onStateChanged(linphone::Call::State state, const std::string &message);
QString getLastErrorMessage() const;
void setLastErrorMessage(const QString &message);
signals:
void statusChanged(LinphoneEnums::CallStatus status);
void stateChanged(LinphoneEnums::CallState state);
void lastErrorMessageChanged();
// Linphone commands
void lAccept(bool withVideo); // Accept an incoming call
void lDecline(); // Decline an incoming call
void lTerminate(); // Hangup a call
/* TODO
Q_INVOKABLE void acceptWithVideo();
Q_INVOKABLE void askForTransfer();
Q_INVOKABLE void askForAttendedTransfer();
Q_INVOKABLE bool transferTo(const QString &sipAddress);
Q_INVOKABLE bool transferToAnother(const QString &peerAddress);
Q_INVOKABLE bool getRemoteVideoEnabled() const;
Q_INVOKABLE void acceptVideoRequest();
Q_INVOKABLE void rejectVideoRequest();
Q_INVOKABLE void takeSnapshot();
Q_INVOKABLE void startRecording();
Q_INVOKABLE void stopRecording();
Q_INVOKABLE void sendDtmf(const QString &dtmf);
Q_INVOKABLE void verifyAuthenticationToken(bool verify);
Q_INVOKABLE void updateStreams();
Q_INVOKABLE void toggleSpeakerMute();
*/
private:
std::shared_ptr<CallModel> mCallModel;
LinphoneEnums::CallStatus mStatus;
LinphoneEnums::CallState mState;
QString mLastErrorMessage;
DECLARE_ABSTRACT_OBJECT
};
Q_DECLARE_METATYPE(Call *)
#endif

View file

@ -0,0 +1,420 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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 <QFileInfo>
#include <QMutex>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QQmlContext>
#include <QQuickItem>
#include <QQuickView>
#include <QQuickWindow>
#include <QScreen>
#include <QTimer>
#include "Notifier.hpp"
#include "core/App.hpp"
#include "core/call/Call.hpp"
#include "tool/LinphoneEnums.hpp"
#include "tool/providers/ImageProvider.hpp"
DEFINE_ABSTRACT_OBJECT(Notifier)
// =============================================================================
using namespace std;
namespace {
constexpr char NotificationsPath[] = "qrc:/Linphone/view/Item/Notification/";
// ---------------------------------------------------------------------------
// Notifications QML properties/methods.
// ---------------------------------------------------------------------------
constexpr char NotificationShowMethodName[] = "open";
constexpr char NotificationPropertyData[] = "notificationData";
constexpr char NotificationPropertyX[] = "popupX";
constexpr char NotificationPropertyY[] = "popupY";
constexpr char NotificationPropertyWindow[] = "__internalWindow";
constexpr char NotificationPropertyTimer[] = "__timer";
// ---------------------------------------------------------------------------
// Arbitrary hardcoded values.
// ---------------------------------------------------------------------------
constexpr int NotificationSpacing = 10;
constexpr int MaxNotificationsNumber = 5;
} // namespace
// =============================================================================
template <class T>
void setProperty(QObject &object, const char *property, const T &value) {
if (!object.setProperty(property, QVariant(value))) {
qWarning() << QStringLiteral("Unable to set property: `%1`.").arg(property);
abort();
}
}
// =============================================================================
// Available notifications.
// =============================================================================
const QHash<int, Notifier::Notification> Notifier::Notifications = {
//{Notifier::ReceivedMessage, {Notifier::ReceivedMessage, "NotificationReceivedMessage.qml", 10}},
//{Notifier::ReceivedFileMessage, {Notifier::ReceivedFileMessage, "NotificationReceivedFileMessage.qml", 10}},
{Notifier::ReceivedCall, {Notifier::ReceivedCall, "NotificationReceivedCall.qml", 30}},
//{Notifier::NewVersionAvailable, {Notifier::NewVersionAvailable, "NotificationNewVersionAvailable.qml", 30}},
//{Notifier::SnapshotWasTaken, {Notifier::SnapshotWasTaken, "NotificationSnapshotWasTaken.qml", 10}},
//{Notifier::RecordingCompleted, {Notifier::RecordingCompleted, "NotificationRecordingCompleted.qml", 10}}
};
// -----------------------------------------------------------------------------
Notifier::Notifier(QObject *parent) : QObject(parent) {
mustBeInMainThread(getClassName());
const int nComponents = Notifications.size();
mComponents = new QQmlComponent *[nComponents];
QQmlEngine *engine = App::getInstance()->mEngine;
for (const auto &key : Notifications.keys()) {
QQmlComponent *component =
new QQmlComponent(engine, QUrl(NotificationsPath + Notifier::Notifications[key].filename));
if (Q_UNLIKELY(component->isError())) {
qWarning() << QStringLiteral("Errors found in `Notification` component %1:").arg(key)
<< component->errors();
abort();
}
mComponents[key] = component;
}
mMutex = new QMutex();
}
Notifier::~Notifier() {
mustBeInMainThread("~" + getClassName());
delete mMutex;
const int nComponents = Notifications.size();
for (int i = 0; i < nComponents; ++i)
mComponents[i]->deleteLater();
delete[] mComponents;
}
// -----------------------------------------------------------------------------
QObject *Notifier::createNotification(Notifier::NotificationType type, QVariantMap data) {
QQuickItem *wrapperItem = nullptr;
mMutex->lock();
Q_ASSERT(mInstancesNumber <= MaxNotificationsNumber);
if (mInstancesNumber == MaxNotificationsNumber) { // Check existing instances.
qWarning() << QStringLiteral("Unable to create another notification.");
mMutex->unlock();
return nullptr;
}
QList<QScreen *> allScreens = QGuiApplication::screens();
if (allScreens.size() > 0) { // Ensure to have a screen to avoid errors
QQuickItem *previousWrapper = nullptr;
++mInstancesNumber;
bool showAsTool = false;
#ifdef Q_OS_MACOS
for (auto w : QGuiApplication::topLevelWindows()) {
if ((w->windowState() & Qt::WindowFullScreen) == Qt::WindowFullScreen) {
showAsTool = true;
w->raise(); // Used to get focus on Mac (On Mac, A Tool is hidden if the app has not focus and the only
// way to rid it is to use Widget Attributes(Qt::WA_MacAlwaysShowToolWindow) that is not
// available)
}
}
#endif
for (int i = 0; i < allScreens.size(); ++i) {
// Use QQuickView to create a visual root object that is
// independant from current application Window
QScreen *screen = allScreens[i];
// auto engine = App::getInstance()->mEngine;
auto engine = new QQmlApplicationEngine();
engine->addImageProvider(ImageProvider::ProviderId, new ImageProvider());
engine->addImportPath(":/");
// if(showAsTool) window->setProperty("showAsTool",true);
engine->setInitialProperties(data);
// engine->rootContext()->setContextProperty("applicationDirPath",QGuiApplication::applicationDirPath());
// engine->setInitialProperties({{"screenIndex", i}});
//, {"x", screen->geometry().x()}, {"y", screen->geometry().y()}});
const QUrl url(QString(NotificationsPath) + Notifier::Notifications[type].filename);
QObject::connect(
engine, &QQmlApplicationEngine::objectCreated, this,
[this, url, screen, engine](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl) {
qCritical() << "[App] Notifier.qml couldn't be load.";
engine->deleteLater();
exit(-1);
} else {
qWarning() << engine->rootObjects()[0];
auto window = qobject_cast<QQuickWindow *>(obj);
if (window) {
int *screenHeightOffset = &mScreenHeightOffset[screen->name()]; // Access optimization
QRect availableGeometry = screen->availableGeometry();
int heightOffset =
availableGeometry.y() +
(availableGeometry.height() -
window->height()); //*screen->devicePixelRatio(); when using manual scaler
window->setX(availableGeometry.x() +
(availableGeometry.width() -
window->property("width")
.toInt())); //*screen->devicePixelRatio()); when using manual scaler
window->setY(heightOffset - (*screenHeightOffset % heightOffset));
qWarning() << window->geometry();
}
}
},
Qt::QueuedConnection);
engine->load(url);
}
qInfo() << QStringLiteral("Create notifications:") << wrapperItem;
}
mMutex->unlock();
return wrapperItem;
}
// -----------------------------------------------------------------------------
void Notifier::showNotification(QObject *notification, int timeout) {
// Display notification.
QMetaObject::invokeMethod(notification, NotificationShowMethodName, Qt::DirectConnection);
QTimer *timer = new QTimer(notification);
timer->setInterval(timeout);
timer->setSingleShot(true);
notification->setProperty(NotificationPropertyTimer, QVariant::fromValue(timer));
// Destroy it after timeout.
QObject::connect(timer, &QTimer::timeout, this,
[this, notification]() { deleteNotificationOnTimeout(QVariant::fromValue(notification)); });
// Called explicitly (by a click on notification for example)
QObject::connect(notification, SIGNAL(deleteNotification(QVariant)), this, SLOT(deleteNotification(QVariant)));
timer->start();
}
// -----------------------------------------------------------------------------
void Notifier::deleteNotificationOnTimeout(QVariant notification) {
#ifdef Q_OS_MACOS
for (auto w : QGuiApplication::topLevelWindows()) {
if ((w->windowState() & Qt::WindowFullScreen) == Qt::WindowFullScreen) {
w->requestActivate(); // Used to get focus on fullscreens on Mac in order to avoid screen switching.
}
}
#endif
deleteNotification(notification);
}
void Notifier::deleteNotification(QVariant notification) {
mMutex->lock();
QObject *instance = notification.value<QObject *>();
// Notification marked destroyed.
if (instance->property("__valid").isValid()) {
mMutex->unlock();
return;
}
qInfo() << QStringLiteral("Delete notification:") << instance;
instance->setProperty("__valid", true);
instance->property(NotificationPropertyTimer).value<QTimer *>()->stop();
mInstancesNumber--;
Q_ASSERT(mInstancesNumber >= 0);
if (mInstancesNumber == 0) mScreenHeightOffset.clear();
mMutex->unlock();
instance->deleteLater();
}
// =============================================================================
#define CREATE_NOTIFICATION(TYPE, DATA) \
QObject *notification = createNotification(TYPE, DATA); \
if (!notification) return; \
const int timeout = Notifications[TYPE].getTimeout() * 1000; \
showNotification(notification, timeout);
// -----------------------------------------------------------------------------
// Notification functions.
// -----------------------------------------------------------------------------
void Notifier::notifyReceivedCall(const shared_ptr<linphone::Call> &call) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto model = new Call(call);
model->moveToThread(this->thread());
App::postCoreAsync([this, model]() {
mustBeInMainThread(getClassName());
QVariantMap map;
map["call"].setValue(model);
CREATE_NOTIFICATION(Notifier::ReceivedCall, map)
QObject::connect(
model, &Call::statusChanged, notification, [this, notification](LinphoneEnums::CallStatus status) {
qInfo() << log().arg("Delete notification on call status : %1").arg(LinphoneEnums::toString(status));
deleteNotification(QVariant::fromValue(notification));
});
QObject::connect(model, &Call::destroyed, notification,
[this, notification]() { deleteNotification(QVariant::fromValue(notification)); });
});
}
/*
void Notifier::notifyReceivedMessages(const list<shared_ptr<linphone::ChatMessage>> &messages) {
QVariantMap map;
QString txt;
if (messages.size() > 0) {
shared_ptr<linphone::ChatMessage> message = messages.front();
if (messages.size() == 1) {
auto fileContent = message->getFileTransferInformation();
if (!fileContent) {
foreach (auto content, message->getContents()) {
if (content->isText()) txt += content->getUtf8Text().c_str();
}
} else if (fileContent->isVoiceRecording())
//: 'Voice message received!' : message to warn the user in a notofication for voice messages.
txt = tr("newVoiceMessage");
else txt = tr("newFileMessage");
if (txt.isEmpty() && message->hasConferenceInvitationContent())
//: 'Conference invitation received!' : Notification about receiving an invitation to a conference.
txt = tr("newConferenceInvitation");
} else
//: 'New messages received!' Notification that warn the user of new messages.
txt = tr("newChatRoomMessages");
map["message"] = txt;
shared_ptr<linphone::ChatRoom> chatRoom(message->getChatRoom());
map["timelineModel"].setValue(
CoreManager::getInstance()->getTimelineListModel()->getTimeline(chatRoom, true).get());
if (messages.size() == 1) { // Display only sender on mono message.
map["peerAddress"] = Utils::coreStringToAppString(message->getFromAddress()->asStringUriOnly());
map["fullPeerAddress"] = Utils::coreStringToAppString(message->getFromAddress()->asString());
}
map["localAddress"] = Utils::coreStringToAppString(message->getToAddress()->asStringUriOnly());
map["fullLocalAddress"] = Utils::coreStringToAppString(message->getToAddress()->asString());
map["window"].setValue(App::getInstance()->getMainWindow());
CREATE_NOTIFICATION(Notifier::ReceivedMessage, map)
}
}
void Notifier::notifyReceivedReactions(
const QList<QPair<std::shared_ptr<linphone::ChatMessage>, std::shared_ptr<const linphone::ChatMessageReaction>>>
&reactions) {
QVariantMap map;
QString txt;
if (reactions.size() > 0) {
ChatMessageModel *redirection = nullptr;
QPair<shared_ptr<linphone::ChatMessage>, std::shared_ptr<const linphone::ChatMessageReaction>> reaction =
reactions.front();
shared_ptr<linphone::ChatMessage> message = reaction.first;
shared_ptr<linphone::ChatRoom> chatRoom(message->getChatRoom());
auto timelineModel = CoreManager::getInstance()->getTimelineListModel()->getTimeline(chatRoom, true);
map["messageId"] = Utils::coreStringToAppString(message->getMessageId());
if (reactions.size() == 1) {
QString messageTxt;
auto fileContent = message->getFileTransferInformation();
if (!fileContent) {
foreach (auto content, message->getContents()) {
if (content->isText()) messageTxt += content->getUtf8Text().c_str();
}
} else if (fileContent->isVoiceRecording())
//: 'Voice message' : Voice message type that has been reacted.
messageTxt += tr("voiceMessageReact");
else {
QFileInfo file(Utils::coreStringToAppString(fileContent->getFilePath()));
messageTxt += file.fileName();
}
if (messageTxt.isEmpty() && message->hasConferenceInvitationContent())
//: 'Conference invitation' : Conference invitation message type that has been reacted.
messageTxt += tr("conferenceInvitationReact");
//: ''Has reacted by %1 to: %2' : Reaction message. %1=Reaction(emoji), %2=type of message(Voice
//: Message/Conference invitation/ Message text)
txt = tr("reactionMessage").arg(Utils::coreStringToAppString(reaction.second->getBody())).arg(messageTxt);
} else
//: 'New reactions received!' : Notification that warn the user of new reactions.
txt = tr("newReactionsMessages");
map["message"] = txt;
map["timelineModel"].setValue(timelineModel.get());
if (reactions.size() == 1) { // Display only sender on mono message.
map["peerAddress"] = Utils::coreStringToAppString(reaction.second->getFromAddress()->asStringUriOnly());
map["fullPeerAddress"] = Utils::coreStringToAppString(reaction.second->getFromAddress()->asString());
}
map["localAddress"] = Utils::coreStringToAppString(chatRoom->getLocalAddress()->asStringUriOnly());
map["fullLocalAddress"] = Utils::coreStringToAppString(chatRoom->getLocalAddress()->asString());
map["window"].setValue(App::getInstance()->getMainWindow());
CREATE_NOTIFICATION(Notifier::ReceivedMessage, map)
}
}
void Notifier::notifyReceivedFileMessage(const shared_ptr<linphone::ChatMessage> &message,
const shared_ptr<linphone::Content> &content) {
QVariantMap map;
shared_ptr<linphone::ChatRoom> chatRoom(message->getChatRoom());
map["timelineModel"].setValue(
CoreManager::getInstance()->getTimelineListModel()->getTimeline(chatRoom, true).get());
map["fileUri"] = Utils::coreStringToAppString(content->getFilePath());
if (Utils::getImage(map["fileUri"].toString()).isNull()) map["imageUri"] = "";
else map["imageUri"] = map["fileUri"];
map["fileSize"] = quint64(content->getSize() + content->getFileSize());
CREATE_NOTIFICATION(Notifier::ReceivedFileMessage, map)
}
void Notifier::notifyNewVersionAvailable(const QString &version, const QString &url) {
QVariantMap map;
map["message"] = tr("newVersionAvailable").arg(version);
map["url"] = url;
CREATE_NOTIFICATION(Notifier::NewVersionAvailable, map)
}
void Notifier::notifySnapshotWasTaken(const QString &filePath) {
QVariantMap map;
map["filePath"] = filePath;
CREATE_NOTIFICATION(Notifier::SnapshotWasTaken, map)
}
void Notifier::notifyRecordingCompleted(const QString &filePath) {
QVariantMap map;
map["filePath"] = filePath;
CREATE_NOTIFICATION(Notifier::RecordingCompleted, map)
}
*/
#undef SHOW_NOTIFICATION
#undef CREATE_NOTIFICATION

View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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/>.
*/
#ifndef NOTIFIER_H_
#define NOTIFIER_H_
#include <memory>
#include "core/call/Call.hpp"
#include "tool/AbstractObject.hpp"
#include <QHash>
#include <QObject>
// =============================================================================
class QMutex;
class QQmlComponent;
class Notifier : public QObject, public AbstractObject {
Q_OBJECT
public:
Notifier(QObject *parent = Q_NULLPTR);
~Notifier();
enum NotificationType {
ReceivedMessage,
ReceivedFileMessage,
ReceivedCall,
NewVersionAvailable,
SnapshotWasTaken,
RecordingCompleted
};
// void notifyReceivedCall(Call *call);
void notifyReceivedCall(const std::shared_ptr<linphone::Call> &call); // Call from Linphone
/*
void notifyReceivedMessages(const std::list<std::shared_ptr<linphone::ChatMessage>> &messages);
void notifyReceivedReactions(
const QList<QPair<std::shared_ptr<linphone::ChatMessage>, std::shared_ptr<const
linphone::ChatMessageReaction>>> &reactions); void notifyReceivedFileMessage(const
std::shared_ptr<linphone::ChatMessage> &message, const std::shared_ptr<linphone::Content> &content);
void notifyNewVersionAvailable(const QString &version, const QString &url);
void notifySnapshotWasTaken(const QString &filePath);
void notifyRecordingCompleted(const QString &filePath);
*/
public slots:
void deleteNotificationOnTimeout(QVariant notification);
void deleteNotification(QVariant notification);
private:
struct Notification {
Notification(const int &type = 0, const QString &filename = QString(""), int timeout = 0) {
this->type = type;
this->filename = filename;
this->timeout = timeout;
}
int getTimeout() const {
if (type == Notifier::ReceivedCall) {
// return CoreManager::getInstance()->getSettingsModel()->getIncomingCallTimeout();
return 30;
} else return timeout;
}
QString filename;
private:
int timeout;
int type;
};
QObject *createNotification(NotificationType type, QVariantMap data);
void showNotification(QObject *notification, int timeout);
QHash<QString, int> mScreenHeightOffset;
int mInstancesNumber = 0;
QMutex *mMutex = nullptr;
QQmlComponent **mComponents = nullptr;
static const QHash<int, Notification> Notifications;
DECLARE_ABSTRACT_OBJECT
};
#endif // NOTIFIER_H_

View file

@ -3,10 +3,31 @@
#include <QLocale>
#include <QTranslator>
#include <qloggingcategory.h>
#include "core/App.hpp"
#ifdef QT_QML_DEBUG
#include <QQmlDebuggingEnabler>
#endif
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 10)
// From 5.15.2 to 5.15.10, sometimes, Accessibility freeze the application : Deactivate handlers.
#define ACCESSBILITY_WORKAROUND
#include <QAccessible>
#include <QAccessibleEvent>
void DummyUpdateHandler(QAccessibleEvent *event) {
}
void DummyRootObjectHandler(QObject *) {
}
#endif
int main(int argc, char *argv[]) {
// Useful to share camera on Fullscreen (other context) or multiscreens
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
// Disable QML cache. Avoid malformed cache.
qputenv("QML_DISABLE_DISK_CACHE", "true");
App app(argc, argv);
QTranslator translator;
@ -19,6 +40,11 @@ int main(int argc, char *argv[]) {
}
}
#ifdef ACCESSBILITY_WORKAROUND
QAccessible::installUpdateHandler(DummyUpdateHandler);
QAccessible::installRootObjectHandler(DummyRootObjectHandler);
#endif
int result = 0;
while (result >= 0) {
result = app.exec();

View file

@ -1,9 +1,10 @@
list(APPEND _LINPHONEAPP_SOURCES
model/account/AccountModel.cpp
model/account/AccountManager.cpp
model/call/CallModel.cpp
model/core/CoreModel.cpp
model/core/CoreListener.cpp
model/listener/Listener.hpp

View file

@ -93,6 +93,7 @@ void AccountManager::onRegistrationStateChanged(const std::shared_ptr<linphone::
mAccountModel = nullptr;
break;
case linphone::RegistrationState::Ok:
core->setDefaultAccount(account);
emit mAccountModel->removeListener();
mAccountModel = nullptr;
break;

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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 "CallModel.hpp"
#include <QDebug>
#include "model/core/CoreModel.hpp"
DEFINE_ABSTRACT_OBJECT(CallModel)
CallModel::CallModel(const std::shared_ptr<linphone::Call> &call, QObject *parent)
: ::Listener<linphone::Call, linphone::CallListener>(call, parent) {
mustBeInLinphoneThread(getClassName());
}
CallModel::~CallModel() {
mustBeInLinphoneThread("~" + getClassName());
}
void CallModel::accept(bool withVideo) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto core = CoreModel::getInstance()->getCore();
auto params = core->createCallParams(mMonitor);
params->enableVideo(withVideo);
// Answer with local call address.
auto localAddress = mMonitor->getCallLog()->getLocalAddress();
for (auto account : core->getAccountList()) {
if (account->getParams()->getIdentityAddress()->weakEqual(localAddress)) {
params->setAccount(account);
break;
}
}
mMonitor->acceptWithParams(params);
}
void CallModel::decline() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto errorInfo = linphone::Factory::get()->createErrorInfo();
errorInfo->set("SIP", linphone::Reason::Declined, 603, "Decline", "");
mMonitor->terminateWithErrorInfo(errorInfo);
}
void CallModel::terminate() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mMonitor->terminate();
}
void CallModel::onDtmfReceived(const std::shared_ptr<linphone::Call> &call, int dtmf) {
emit dtmfReceived(call, dtmf);
}
void CallModel::onGoclearAckSent(const std::shared_ptr<linphone::Call> &call) {
emit goclearAckSent(call);
}
void CallModel::onEncryptionChanged(const std::shared_ptr<linphone::Call> &call,
bool on,
const std::string &authenticationToken) {
emit encryptionChanged(call, on, authenticationToken);
}
void CallModel::onSendMasterKeyChanged(const std::shared_ptr<linphone::Call> &call, const std::string &sendMasterKey) {
emit sendMasterKeyChanged(call, sendMasterKey);
}
void CallModel::onReceiveMasterKeyChanged(const std::shared_ptr<linphone::Call> &call,
const std::string &receiveMasterKey) {
emit receiveMasterKeyChanged(call, receiveMasterKey);
}
void CallModel::onInfoMessageReceived(const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<const linphone::InfoMessage> &message) {
emit infoMessageReceived(call, message);
}
void CallModel::onStateChanged(const std::shared_ptr<linphone::Call> &call,
linphone::Call::State state,
const std::string &message) {
emit stateChanged(state, message);
}
void CallModel::onStatsUpdated(const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<const linphone::CallStats> &stats) {
emit statsUpdated(call, stats);
}
void CallModel::onTransferStateChanged(const std::shared_ptr<linphone::Call> &call, linphone::Call::State state) {
emit transferStateChanged(call, state);
}
void CallModel::onAckProcessing(const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<linphone::Headers> &ack,
bool isReceived) {
emit ackProcessing(call, ack, isReceived);
}
void CallModel::onTmmbrReceived(const std::shared_ptr<linphone::Call> &call, int streamIndex, int tmmbr) {
emit tmmbrReceived(call, streamIndex, tmmbr);
}
void CallModel::onSnapshotTaken(const std::shared_ptr<linphone::Call> &call, const std::string &filePath) {
emit snapshotTaken(call, filePath);
}
void CallModel::onNextVideoFrameDecoded(const std::shared_ptr<linphone::Call> &call) {
emit nextVideoFrameDecoded(call);
}
void CallModel::onCameraNotWorking(const std::shared_ptr<linphone::Call> &call, const std::string &cameraName) {
emit cameraNotWorking(call, cameraName);
}
void CallModel::onVideoDisplayErrorOccurred(const std::shared_ptr<linphone::Call> &call, int errorCode) {
emit videoDisplayErrorOccurred(call, errorCode);
}
void CallModel::onAudioDeviceChanged(const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<linphone::AudioDevice> &audioDevice) {
emit audioDeviceChanged(call, audioDevice);
}
void CallModel::onRemoteRecording(const std::shared_ptr<linphone::Call> &call, bool recording) {
emit remoteRecording(call, recording);
}

View file

@ -0,0 +1,105 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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/>.
*/
#ifndef CALL_MODEL_H_
#define CALL_MODEL_H_
#include "model/listener/Listener.hpp"
#include "tool/AbstractObject.hpp"
#include <QObject>
#include <linphone++/linphone.hh>
class CallModel : public ::Listener<linphone::Call, linphone::CallListener>,
public linphone::CallListener,
public AbstractObject {
Q_OBJECT
public:
CallModel(const std::shared_ptr<linphone::Call> &account, QObject *parent = nullptr);
~CallModel();
void accept(bool withVideo);
void decline();
void terminate();
private:
DECLARE_ABSTRACT_OBJECT
//--------------------------------------------------------------------------------
// LINPHONE
//--------------------------------------------------------------------------------
virtual void onDtmfReceived(const std::shared_ptr<linphone::Call> &call, int dtmf) override;
virtual void onGoclearAckSent(const std::shared_ptr<linphone::Call> &call) override;
virtual void onEncryptionChanged(const std::shared_ptr<linphone::Call> &call,
bool on,
const std::string &authenticationToken) override;
virtual void onSendMasterKeyChanged(const std::shared_ptr<linphone::Call> &call,
const std::string &sendMasterKey) override;
virtual void onReceiveMasterKeyChanged(const std::shared_ptr<linphone::Call> &call,
const std::string &receiveMasterKey) override;
virtual void onInfoMessageReceived(const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<const linphone::InfoMessage> &message) override;
virtual void onStateChanged(const std::shared_ptr<linphone::Call> &call,
linphone::Call::State state,
const std::string &message) override;
virtual void onStatsUpdated(const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<const linphone::CallStats> &stats) override;
virtual void onTransferStateChanged(const std::shared_ptr<linphone::Call> &call,
linphone::Call::State state) override;
virtual void onAckProcessing(const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<linphone::Headers> &ack,
bool isReceived) override;
virtual void onTmmbrReceived(const std::shared_ptr<linphone::Call> &call, int streamIndex, int tmmbr) override;
virtual void onSnapshotTaken(const std::shared_ptr<linphone::Call> &call, const std::string &filePath) override;
virtual void onNextVideoFrameDecoded(const std::shared_ptr<linphone::Call> &call) override;
virtual void onCameraNotWorking(const std::shared_ptr<linphone::Call> &call,
const std::string &cameraName) override;
virtual void onVideoDisplayErrorOccurred(const std::shared_ptr<linphone::Call> &call, int errorCode) override;
virtual void onAudioDeviceChanged(const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<linphone::AudioDevice> &audioDevice) override;
virtual void onRemoteRecording(const std::shared_ptr<linphone::Call> &call, bool recording) override;
signals:
void dtmfReceived(const std::shared_ptr<linphone::Call> &call, int dtmf);
void goclearAckSent(const std::shared_ptr<linphone::Call> &call);
void
encryptionChanged(const std::shared_ptr<linphone::Call> &call, bool on, const std::string &authenticationToken);
void sendMasterKeyChanged(const std::shared_ptr<linphone::Call> &call, const std::string &sendMasterKey);
void receiveMasterKeyChanged(const std::shared_ptr<linphone::Call> &call, const std::string &receiveMasterKey);
void infoMessageReceived(const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<const linphone::InfoMessage> &message);
void stateChanged(linphone::Call::State state, const std::string &message);
void statsUpdated(const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<const linphone::CallStats> &stats);
void transferStateChanged(const std::shared_ptr<linphone::Call> &call, linphone::Call::State state);
void ackProcessing(const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<linphone::Headers> &ack,
bool isReceived);
void tmmbrReceived(const std::shared_ptr<linphone::Call> &call, int streamIndex, int tmmbr);
void snapshotTaken(const std::shared_ptr<linphone::Call> &call, const std::string &filePath);
void nextVideoFrameDecoded(const std::shared_ptr<linphone::Call> &call);
void cameraNotWorking(const std::shared_ptr<linphone::Call> &call, const std::string &cameraName);
void videoDisplayErrorOccurred(const std::shared_ptr<linphone::Call> &call, int errorCode);
virtual void audioDeviceChanged(const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<linphone::AudioDevice> &audioDevice);
void remoteRecording(const std::shared_ptr<linphone::Call> &call, bool recording);
};
#endif

View file

@ -1,161 +0,0 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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) {
}
CoreListener::~CoreListener() {
}
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::onAuthenticationRequested(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::AuthInfo> &authInfo,
linphone::AuthMethod method) {
emit authenticationRequested(core, authInfo, method);
}
void CoreListener::onCallEncryptionChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
bool on,
const std::string &authenticationToken) {
emit callEncryptionChanged(core, call, on, authenticationToken);
}
void CoreListener::onCallLogUpdated(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::CallLog> &callLog) {
emit callLogUpdated(core, callLog);
}
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::onCallStatsUpdated(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<const linphone::CallStats> &stats) {
emit callStatsUpdated(core, call, stats);
}
void CoreListener::onCallCreated(const std::shared_ptr<linphone::Core> &lc,
const std::shared_ptr<linphone::Call> &call) {
emit callCreated(lc, call);
}
void CoreListener::onChatRoomRead(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom) {
emit chatRoomRead(core, chatRoom);
}
void CoreListener::onChatRoomStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
linphone::ChatRoom::State state) {
emit chatRoomStateChanged(core, chatRoom, state);
}
void CoreListener::onConferenceInfoReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo) {
emit conferenceInfoReceived(core, conferenceInfo);
}
void CoreListener::onConfiguringStatus(const std::shared_ptr<linphone::Core> &core,
linphone::Config::ConfiguringState status,
const std::string &message) {
emit configuringStatus(core, status, message);
}
void CoreListener::onDtmfReceived(const std::shared_ptr<linphone::Core> &lc,
const std::shared_ptr<linphone::Call> &call,
int dtmf) {
emit dtmfReceived(lc, call, dtmf);
}
void CoreListener::onEcCalibrationResult(const std::shared_ptr<linphone::Core> &core,
linphone::EcCalibratorStatus status,
int delayMs) {
emit ecCalibrationResult(core, status, delayMs);
}
void CoreListener::onGlobalStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::GlobalState gstate,
const std::string &message) {
emit globalStateChanged(core, gstate, message);
}
void CoreListener::onIsComposingReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room) {
emit isComposingReceived(core, room);
}
void CoreListener::onLogCollectionUploadStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::Core::LogCollectionUploadState state,
const std::string &info) {
emit logCollectionUploadStateChanged(core, state, info);
}
void CoreListener::onLogCollectionUploadProgressIndication(const std::shared_ptr<linphone::Core> &lc,
size_t offset,
size_t total) {
emit logCollectionUploadProgressIndication(lc, offset, total);
}
void CoreListener::onMessageReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room,
const std::shared_ptr<linphone::ChatMessage> &message) {
emit messageReceived(core, room, message);
}
void CoreListener::onMessagesReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room,
const std::list<std::shared_ptr<linphone::ChatMessage>> &messages) {
emit messagesReceived(core, room, messages);
}
void CoreListener::onNewMessageReaction(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<linphone::ChatMessage> &message,
const std::shared_ptr<const linphone::ChatMessageReaction> &reaction) {
emit newMessageReaction(core, chatRoom, message, reaction);
}
void CoreListener::onNotifyPresenceReceivedForUriOrTel(
const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphoneFriend,
const std::string &uriOrTel,
const std::shared_ptr<const linphone::PresenceModel> &presenceModel) {
emit notifyPresenceReceivedForUriOrTel(core, linphoneFriend, uriOrTel, presenceModel);
}
void CoreListener::onNotifyPresenceReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphoneFriend) {
emit notifyPresenceReceived(core, linphoneFriend);
}
void CoreListener::onQrcodeFound(const std::shared_ptr<linphone::Core> &core, const std::string &result) {
emit qrcodeFound(core, result);
}
void CoreListener::onReactionRemoved(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<linphone::ChatMessage> &message,
const std::shared_ptr<const linphone::Address> &address) {
emit reactionRemoved(core, chatRoom, message, address);
}
void CoreListener::onTransferStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
linphone::Call::State state) {
emit transferStateChanged(core, call, state);
}
void CoreListener::onVersionUpdateCheckResultReceived(const std::shared_ptr<linphone::Core> &core,
linphone::VersionUpdateCheckResult result,
const std::string &version,
const std::string &url) {
emit versionUpdateCheckResultReceived(core, result, version, url);
}

View file

@ -1,187 +0,0 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* 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/>.
*/
#ifndef CORE_LISTENER_H_
#define CORE_LISTENER_H_
#include <QObject>
#include <linphone++/linphone.hh>
// =============================================================================
class CoreListener : public QObject, public linphone::CoreListener {
Q_OBJECT
public:
CoreListener(QObject *parent = nullptr);
virtual ~CoreListener();
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 onAuthenticationRequested(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::AuthInfo> &authInfo,
linphone::AuthMethod method) override;
virtual void onCallEncryptionChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
bool on,
const std::string &authenticationToken) override;
virtual void onCallLogUpdated(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::CallLog> &callLog) 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 onCallStatsUpdated(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<const linphone::CallStats> &stats) override;
virtual void onCallCreated(const std::shared_ptr<linphone::Core> &lc,
const std::shared_ptr<linphone::Call> &call) override;
virtual void onChatRoomRead(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom) override;
virtual void onChatRoomStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
linphone::ChatRoom::State state) override;
virtual void
onConferenceInfoReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo) override;
virtual void onConfiguringStatus(const std::shared_ptr<linphone::Core> &core,
linphone::Config::ConfiguringState status,
const std::string &message) override;
virtual void onDtmfReceived(const std::shared_ptr<linphone::Core> &lc,
const std::shared_ptr<linphone::Call> &call,
int dtmf) override;
virtual void onEcCalibrationResult(const std::shared_ptr<linphone::Core> &core,
linphone::EcCalibratorStatus status,
int delayMs) override;
virtual void onGlobalStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::GlobalState gstate,
const std::string &message) override;
virtual void onIsComposingReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room) override;
virtual void onLogCollectionUploadStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::Core::LogCollectionUploadState state,
const std::string &info) override;
virtual void onLogCollectionUploadProgressIndication(const std::shared_ptr<linphone::Core> &lc,
size_t offset,
size_t total) override;
virtual void onMessageReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room,
const std::shared_ptr<linphone::ChatMessage> &message) override;
virtual void onMessagesReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room,
const std::list<std::shared_ptr<linphone::ChatMessage>> &messages) override;
virtual void onNewMessageReaction(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<linphone::ChatMessage> &message,
const std::shared_ptr<const linphone::ChatMessageReaction> &reaction) override;
virtual void
onNotifyPresenceReceivedForUriOrTel(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphoneFriend,
const std::string &uriOrTel,
const std::shared_ptr<const linphone::PresenceModel> &presenceModel) override;
virtual void onNotifyPresenceReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphoneFriend) override;
virtual void onQrcodeFound(const std::shared_ptr<linphone::Core> &core, const std::string &result) override;
virtual void onReactionRemoved(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<linphone::ChatMessage> &message,
const std::shared_ptr<const linphone::Address> &address) override;
virtual void onTransferStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
linphone::Call::State state) override;
virtual void onVersionUpdateCheckResultReceived(const std::shared_ptr<linphone::Core> &core,
linphone::VersionUpdateCheckResult result,
const std::string &version,
const std::string &url) 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 authenticationRequested(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::AuthInfo> &authInfo,
linphone::AuthMethod method);
void callEncryptionChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
bool on,
const std::string &authenticationToken);
void callLogUpdated(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::CallLog> &callLog);
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 callStatsUpdated(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<const linphone::CallStats> &stats);
void callCreated(const std::shared_ptr<linphone::Core> &lc, const std::shared_ptr<linphone::Call> &call);
void chatRoomRead(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::ChatRoom> &chatRoom);
void chatRoomStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
linphone::ChatRoom::State state);
void conferenceInfoReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo);
void configuringStatus(const std::shared_ptr<linphone::Core> &core,
linphone::Config::ConfiguringState status,
const std::string &message);
void dtmfReceived(const std::shared_ptr<linphone::Core> &lc, const std::shared_ptr<linphone::Call> &call, int dtmf);
void
ecCalibrationResult(const std::shared_ptr<linphone::Core> &core, linphone::EcCalibratorStatus status, int delayMs);
void globalStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::GlobalState gstate,
const std::string &message);
void isComposingReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room);
void logCollectionUploadStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::Core::LogCollectionUploadState state,
const std::string &info);
void logCollectionUploadProgressIndication(const std::shared_ptr<linphone::Core> &lc, size_t offset, size_t total);
void messageReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room,
const std::shared_ptr<linphone::ChatMessage> &message);
void messagesReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room,
const std::list<std::shared_ptr<linphone::ChatMessage>> &messages);
void newMessageReaction(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<linphone::ChatMessage> &message,
const std::shared_ptr<const linphone::ChatMessageReaction> &reaction);
void notifyPresenceReceivedForUriOrTel(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphoneFriend,
const std::string &uriOrTel,
const std::shared_ptr<const linphone::PresenceModel> &presenceModel);
void notifyPresenceReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphoneFriend);
void qrcodeFound(const std::shared_ptr<linphone::Core> &core, const std::string &result);
void reactionRemoved(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<linphone::ChatMessage> &message,
const std::shared_ptr<const linphone::Address> &address);
void transferStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
linphone::Call::State state);
void versionUpdateCheckResultReceived(const std::shared_ptr<linphone::Core> &core,
linphone::VersionUpdateCheckResult result,
const std::string &version,
const std::string &url);
};
#endif

View file

@ -28,14 +28,17 @@
#include <QTimer>
#include "core/App.hpp"
#include "core/notifier/Notifier.hpp"
#include "core/path/Paths.hpp"
#include "tool/Utils.hpp"
// =============================================================================
DEFINE_ABSTRACT_OBJECT(CoreModel)
QSharedPointer<CoreModel> CoreModel::gCoreModel;
std::shared_ptr<CoreModel> CoreModel::gCoreModel;
CoreModel::CoreModel(const QString &configPath, QThread *parent) : QObject() {
CoreModel::CoreModel(const QString &configPath, QThread *parent)
: ::Listener<linphone::Core, linphone::CoreListener>(nullptr, parent) {
connect(parent, &QThread::finished, this, [this]() {
// Model thread
if (mCore && mCore->getGlobalState() == linphone::GlobalState::On) mCore->stop();
@ -50,8 +53,9 @@ CoreModel::CoreModel(const QString &configPath, QThread *parent) : QObject() {
CoreModel::~CoreModel() {
}
QSharedPointer<CoreModel> CoreModel::create(const QString &configPath, QThread *parent) {
auto model = QSharedPointer<CoreModel>::create(configPath, parent);
std::shared_ptr<CoreModel> CoreModel::create(const QString &configPath, QThread *parent) {
auto model = std::make_shared<CoreModel>(configPath, parent);
model->setSelf(model);
gCoreModel = model;
return model;
}
@ -64,6 +68,7 @@ void CoreModel::start() {
mCore =
linphone::Factory::get()->createCore(Utils::appStringToCoreString(Paths::getConfigFilePath(mConfigPath)),
Utils::appStringToCoreString(Paths::getFactoryConfigFilePath()), nullptr);
setMonitor(mCore);
setPathsAfterCreation();
mCore->start();
setPathAfterStart();
@ -71,7 +76,7 @@ void CoreModel::start() {
}
// -----------------------------------------------------------------------------
QSharedPointer<CoreModel> CoreModel::getInstance() {
std::shared_ptr<CoreModel> CoreModel::getInstance() {
return gCoreModel;
}
@ -131,3 +136,138 @@ void CoreModel::setPathAfterStart() {
mCore->setRootCa(Utils::appStringToCoreString(Paths::getRootCaFilePath()));
qInfo() << "[CoreModel] Using RootCa path : " << QString::fromStdString(mCore->getRootCa());
}
//---------------------------------------------------------------------------------------------------------------------------
void CoreModel::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 CoreModel::onAuthenticationRequested(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::AuthInfo> &authInfo,
linphone::AuthMethod method) {
emit authenticationRequested(core, authInfo, method);
}
void CoreModel::onCallEncryptionChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
bool on,
const std::string &authenticationToken) {
emit callEncryptionChanged(core, call, on, authenticationToken);
}
void CoreModel::onCallLogUpdated(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::CallLog> &callLog) {
emit callLogUpdated(core, callLog);
}
void CoreModel::onCallStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
linphone::Call::State state,
const std::string &message) {
if (state == linphone::Call::State::IncomingReceived) {
App::getInstance()->getNotifier()->notifyReceivedCall(call);
}
emit callStateChanged(core, call, state, message);
}
void CoreModel::onCallStatsUpdated(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<const linphone::CallStats> &stats) {
emit callStatsUpdated(core, call, stats);
}
void CoreModel::onCallCreated(const std::shared_ptr<linphone::Core> &lc, const std::shared_ptr<linphone::Call> &call) {
emit callCreated(lc, call);
}
void CoreModel::onChatRoomRead(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom) {
emit chatRoomRead(core, chatRoom);
}
void CoreModel::onChatRoomStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
linphone::ChatRoom::State state) {
emit chatRoomStateChanged(core, chatRoom, state);
}
void CoreModel::onConferenceInfoReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo) {
emit conferenceInfoReceived(core, conferenceInfo);
}
void CoreModel::onConfiguringStatus(const std::shared_ptr<linphone::Core> &core,
linphone::Config::ConfiguringState status,
const std::string &message) {
emit configuringStatus(core, status, message);
}
void CoreModel::onDtmfReceived(const std::shared_ptr<linphone::Core> &lc,
const std::shared_ptr<linphone::Call> &call,
int dtmf) {
emit dtmfReceived(lc, call, dtmf);
}
void CoreModel::onEcCalibrationResult(const std::shared_ptr<linphone::Core> &core,
linphone::EcCalibratorStatus status,
int delayMs) {
emit ecCalibrationResult(core, status, delayMs);
}
void CoreModel::onGlobalStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::GlobalState gstate,
const std::string &message) {
emit globalStateChanged(core, gstate, message);
}
void CoreModel::onIsComposingReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room) {
emit isComposingReceived(core, room);
}
void CoreModel::onLogCollectionUploadStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::Core::LogCollectionUploadState state,
const std::string &info) {
emit logCollectionUploadStateChanged(core, state, info);
}
void CoreModel::onLogCollectionUploadProgressIndication(const std::shared_ptr<linphone::Core> &lc,
size_t offset,
size_t total) {
emit logCollectionUploadProgressIndication(lc, offset, total);
}
void CoreModel::onMessageReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room,
const std::shared_ptr<linphone::ChatMessage> &message) {
emit messageReceived(core, room, message);
}
void CoreModel::onMessagesReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room,
const std::list<std::shared_ptr<linphone::ChatMessage>> &messages) {
emit messagesReceived(core, room, messages);
}
void CoreModel::onNewMessageReaction(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<linphone::ChatMessage> &message,
const std::shared_ptr<const linphone::ChatMessageReaction> &reaction) {
emit newMessageReaction(core, chatRoom, message, reaction);
}
void CoreModel::onNotifyPresenceReceivedForUriOrTel(
const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphoneFriend,
const std::string &uriOrTel,
const std::shared_ptr<const linphone::PresenceModel> &presenceModel) {
emit notifyPresenceReceivedForUriOrTel(core, linphoneFriend, uriOrTel, presenceModel);
}
void CoreModel::onNotifyPresenceReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphoneFriend) {
emit notifyPresenceReceived(core, linphoneFriend);
}
void CoreModel::onQrcodeFound(const std::shared_ptr<linphone::Core> &core, const std::string &result) {
emit qrcodeFound(core, result);
}
void CoreModel::onReactionRemoved(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<linphone::ChatMessage> &message,
const std::shared_ptr<const linphone::Address> &address) {
emit reactionRemoved(core, chatRoom, message, address);
}
void CoreModel::onTransferStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
linphone::Call::State state) {
emit transferStateChanged(core, call, state);
}
void CoreModel::onVersionUpdateCheckResultReceived(const std::shared_ptr<linphone::Core> &core,
linphone::VersionUpdateCheckResult result,
const std::string &version,
const std::string &url) {
emit versionUpdateCheckResultReceived(core, result, version, url);
}

View file

@ -28,17 +28,21 @@
#include <QTimer>
#include <linphone++/linphone.hh>
#include "model/listener/Listener.hpp"
#include "model/logger/LoggerModel.hpp"
#include "tool/AbstractObject.hpp"
// =============================================================================
class CoreModel : public QObject {
class CoreModel : public ::Listener<linphone::Core, linphone::CoreListener>,
public linphone::CoreListener,
public AbstractObject {
Q_OBJECT
public:
CoreModel(const QString &configPath, QThread *parent);
~CoreModel();
static QSharedPointer<CoreModel> create(const QString &configPath, QThread *parent);
static QSharedPointer<CoreModel> getInstance();
static std::shared_ptr<CoreModel> create(const QString &configPath, QThread *parent);
static std::shared_ptr<CoreModel> getInstance();
std::shared_ptr<linphone::Core> getCore();
@ -61,7 +65,162 @@ private:
void setPathsAfterCreation();
void setPathAfterStart();
static QSharedPointer<CoreModel> gCoreModel;
static std::shared_ptr<CoreModel> gCoreModel;
DECLARE_ABSTRACT_OBJECT
//--------------------------------------------------------------------------------
// LINPHONE
//--------------------------------------------------------------------------------
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 onAuthenticationRequested(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::AuthInfo> &authInfo,
linphone::AuthMethod method) override;
virtual void onCallEncryptionChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
bool on,
const std::string &authenticationToken) override;
virtual void onCallLogUpdated(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::CallLog> &callLog) 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 onCallStatsUpdated(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<const linphone::CallStats> &stats) override;
virtual void onCallCreated(const std::shared_ptr<linphone::Core> &lc,
const std::shared_ptr<linphone::Call> &call) override;
virtual void onChatRoomRead(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom) override;
virtual void onChatRoomStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
linphone::ChatRoom::State state) override;
virtual void
onConferenceInfoReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo) override;
virtual void onConfiguringStatus(const std::shared_ptr<linphone::Core> &core,
linphone::Config::ConfiguringState status,
const std::string &message) override;
virtual void onDtmfReceived(const std::shared_ptr<linphone::Core> &lc,
const std::shared_ptr<linphone::Call> &call,
int dtmf) override;
virtual void onEcCalibrationResult(const std::shared_ptr<linphone::Core> &core,
linphone::EcCalibratorStatus status,
int delayMs) override;
virtual void onGlobalStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::GlobalState gstate,
const std::string &message) override;
virtual void onIsComposingReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room) override;
virtual void onLogCollectionUploadStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::Core::LogCollectionUploadState state,
const std::string &info) override;
virtual void onLogCollectionUploadProgressIndication(const std::shared_ptr<linphone::Core> &lc,
size_t offset,
size_t total) override;
virtual void onMessageReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room,
const std::shared_ptr<linphone::ChatMessage> &message) override;
virtual void onMessagesReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room,
const std::list<std::shared_ptr<linphone::ChatMessage>> &messages) override;
virtual void onNewMessageReaction(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<linphone::ChatMessage> &message,
const std::shared_ptr<const linphone::ChatMessageReaction> &reaction) override;
virtual void
onNotifyPresenceReceivedForUriOrTel(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphoneFriend,
const std::string &uriOrTel,
const std::shared_ptr<const linphone::PresenceModel> &presenceModel) override;
virtual void onNotifyPresenceReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphoneFriend) override;
virtual void onQrcodeFound(const std::shared_ptr<linphone::Core> &core, const std::string &result) override;
virtual void onReactionRemoved(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<linphone::ChatMessage> &message,
const std::shared_ptr<const linphone::Address> &address) override;
virtual void onTransferStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
linphone::Call::State state) override;
virtual void onVersionUpdateCheckResultReceived(const std::shared_ptr<linphone::Core> &core,
linphone::VersionUpdateCheckResult result,
const std::string &version,
const std::string &url) 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 authenticationRequested(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::AuthInfo> &authInfo,
linphone::AuthMethod method);
void callEncryptionChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
bool on,
const std::string &authenticationToken);
void callLogUpdated(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::CallLog> &callLog);
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 callStatsUpdated(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
const std::shared_ptr<const linphone::CallStats> &stats);
void callCreated(const std::shared_ptr<linphone::Core> &lc, const std::shared_ptr<linphone::Call> &call);
void chatRoomRead(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::ChatRoom> &chatRoom);
void chatRoomStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
linphone::ChatRoom::State state);
void conferenceInfoReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo);
void configuringStatus(const std::shared_ptr<linphone::Core> &core,
linphone::Config::ConfiguringState status,
const std::string &message);
void dtmfReceived(const std::shared_ptr<linphone::Core> &lc, const std::shared_ptr<linphone::Call> &call, int dtmf);
void
ecCalibrationResult(const std::shared_ptr<linphone::Core> &core, linphone::EcCalibratorStatus status, int delayMs);
void globalStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::GlobalState gstate,
const std::string &message);
void isComposingReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room);
void logCollectionUploadStateChanged(const std::shared_ptr<linphone::Core> &core,
linphone::Core::LogCollectionUploadState state,
const std::string &info);
void logCollectionUploadProgressIndication(const std::shared_ptr<linphone::Core> &lc, size_t offset, size_t total);
void messageReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room,
const std::shared_ptr<linphone::ChatMessage> &message);
void messagesReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &room,
const std::list<std::shared_ptr<linphone::ChatMessage>> &messages);
void newMessageReaction(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<linphone::ChatMessage> &message,
const std::shared_ptr<const linphone::ChatMessageReaction> &reaction);
void notifyPresenceReceivedForUriOrTel(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphoneFriend,
const std::string &uriOrTel,
const std::shared_ptr<const linphone::PresenceModel> &presenceModel);
void notifyPresenceReceived(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Friend> &linphoneFriend);
void qrcodeFound(const std::shared_ptr<linphone::Core> &core, const std::string &result);
void reactionRemoved(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::ChatRoom> &chatRoom,
const std::shared_ptr<linphone::ChatMessage> &message,
const std::shared_ptr<const linphone::Address> &address);
void transferStateChanged(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::Call> &call,
linphone::Call::State state);
void versionUpdateCheckResultReceived(const std::shared_ptr<linphone::Core> &core,
linphone::VersionUpdateCheckResult result,
const std::string &version,
const std::string &url);
};
#endif

View file

@ -41,7 +41,7 @@ template <class LinphoneClass, class ListenerClass>
class Listener : public ListenerPrivate {
public:
Listener(std::shared_ptr<LinphoneClass> monitor, QObject *parent = nullptr) {
mMonitor = monitor;
setMonitor(monitor);
}
~Listener() {
qDebug() << "Destroying Listener";
@ -50,10 +50,15 @@ public:
virtual void onRemoveListener() {
setSelf(nullptr);
}
void setMonitor(std::shared_ptr<LinphoneClass> monitor) {
if (mMonitor && mSelf) mMonitor->removeListener(mSelf);
mMonitor = monitor;
if (mMonitor && mSelf) mMonitor->addListener(mSelf);
}
void setSelf(const std::shared_ptr<ListenerClass> &self) {
if (mMonitor && mSelf) mMonitor->removeListener(mSelf);
mSelf = self;
if (self) mMonitor->addListener(self);
if (mMonitor && mSelf) mMonitor->addListener(self);
}
protected:

View file

@ -147,7 +147,7 @@ void LoggerModel::init() {
mListener = std::make_shared<LoggerListener>();
connect(mListener.get(), &LoggerListener::logReceived, this, &LoggerModel::onLinphoneLog);
{
std::shared_ptr<linphone::LoggingService> loggingService = linphone::LoggingService::get();
std::shared_ptr<linphone::LoggingService> loggingService = mLoginService = linphone::LoggingService::get();
loggingService->setDomain(Constants::AppDomain);
loggingService->setLogLevel(linphone::LogLevel::Debug);
loggingService->addListener(mListener);

View file

@ -45,15 +45,15 @@ public:
void init();
void init(const std::shared_ptr<linphone::Config> &config);
void onQtLog(QtMsgType type, QString file, int contextLine, QString msg);// Received from Qt
void onQtLog(QtMsgType type, QString file, int contextLine, QString msg); // Received from Qt
void onLinphoneLog(const std::shared_ptr<linphone::LoggingService> &,
const std::string &domain,
linphone::LogLevel level,
const std::string &message);// Received from SDK
const std::string &domain,
linphone::LogLevel level,
const std::string &message); // Received from SDK
signals:
void linphoneLogReceived(const std::string &domain, linphone::LogLevel level, const std::string &message); // Send to Qt
void
linphoneLogReceived(const std::string &domain, linphone::LogLevel level, const std::string &message); // Send to Qt
void verboseEnabledChanged();
void qtOnlyEnabledChanged();
@ -62,6 +62,7 @@ private:
bool mVerboseEnabled = false;
bool mQtOnlyEnabled = false;
std::shared_ptr<LoggerListener> mListener;
std::shared_ptr<linphone::LoggingService> mLoginService; // Need to store one instance to avoid unwanted cleanup.
};
#endif

View file

@ -23,31 +23,40 @@
#include <QDebug>
#include <QTest>
#include "core/App.hpp"
DEFINE_ABSTRACT_OBJECT(VariantObject)
VariantObject::VariantObject(QObject *parent) {
mThreadLocation = false;
mustBeInMainThread(getClassName());
mCoreObject = nullptr;
}
VariantObject::VariantObject(QVariant value, QObject *parent) : mValue(value) {
mThreadLocation = true;
mustBeInMainThread(getClassName());
connect(this, &VariantObject::updateValue, this, &VariantObject::setValue);
mCoreObject = new VariantObject();
connect(this, &VariantObject::valueUpdated, this, &VariantObject::setValue);
mCoreObject = new VariantObject(nullptr);
mCoreObject->moveToThread(CoreModel::getInstance()->thread());
connect(mCoreObject, &VariantObject::valueChanged, this, &VariantObject::setValue);
connect(mCoreObject, &VariantObject::valueChanged, mCoreObject, &QObject::deleteLater);
}
VariantObject::~VariantObject() {
mustBeInMainThread("~" + getClassName());
if (mThreadLocation) mustBeInMainThread("~" + getClassName());
else mustBeInLinphoneThread("~" + getClassName());
}
QVariant VariantObject::getValue() const {
mustBeInMainThread(QString(gClassName) + " : " + Q_FUNC_INFO);
if (mThreadLocation) mustBeInMainThread(QString(gClassName) + " : " + Q_FUNC_INFO);
else mustBeInLinphoneThread(QString(gClassName) + " : " + Q_FUNC_INFO);
return mValue;
}
void VariantObject::setValue(QVariant value) {
mustBeInMainThread(QString(gClassName) + " : " + Q_FUNC_INFO);
if (mThreadLocation) mustBeInMainThread(QString(gClassName) + " : " + Q_FUNC_INFO);
else mustBeInLinphoneThread(QString(gClassName) + " : " + Q_FUNC_INFO);
if (value != mValue) {
mValue = value;
emit valueChanged(mValue);

View file

@ -42,14 +42,17 @@ public:
QVariant getValue() const;
void setValue(QVariant value);
// mCoreObject must be used to request update value : this object will be not be deleted by GUI so it is safe to use
// inside model thread. call emit updateValue() from coreObject to set value from model.
VariantObject *mCoreObject; // Ensure to use DeleteLater() after updating value
signals:
void valueChanged(QVariant value);
void updateValue(QVariant value);
void valueUpdated(QVariant value);
private:
QVariant mValue;
bool mThreadLocation = true; // true=Core, false=Model
DECLARE_ABSTRACT_OBJECT
};

View file

@ -19,9 +19,9 @@
*/
#include "ToolModel.hpp"
#include "core/App.hpp"
#include "model/core/CoreModel.hpp"
#include "tool/Utils.hpp"
#include <QDebug>
#include <QTest>
@ -67,3 +67,58 @@ QString ToolModel::getDisplayName(QString address) {
QString displayName = getDisplayName(interpretUrl(address));
return displayName.isEmpty() ? address : displayName;
}
Call *ToolModel::startAudioCall(const QString &sipAddress,
const QString &prepareTransfertAddress,
const QHash<QString, QString> &headers) {
bool waitRegistrationForCall = true; // getSettingsModel()->getWaitRegistrationForCall()
std::shared_ptr<linphone::Core> core = CoreModel::getInstance()->getCore();
std::shared_ptr<linphone::Address> address = interpretUrl(sipAddress);
if (!address) {
qCritical() << "[" + QString(gClassName) + "] The calling address is not an interpretable SIP address: "
<< sipAddress;
return nullptr;
}
std::shared_ptr<linphone::CallParams> params = core->createCallParams(nullptr);
params->enableVideo(false);
QHashIterator<QString, QString> iterator(headers);
while (iterator.hasNext()) {
iterator.next();
params->addCustomHeader(Utils::appStringToCoreString(iterator.key()),
Utils::appStringToCoreString(iterator.value()));
}
if (core->getDefaultAccount()) params->setAccount(core->getDefaultAccount());
// CallModel::setRecordFile(params, Utils::coreStringToAppString(address->getUsername()));
auto call = core->inviteAddressWithParams(address, params);
return call ? new Call(call) : nullptr;
/* TODO transfer
std::shared_ptr<linphone::Account> currentAccount = core->getDefaultAccount();
if (currentAccount) {
if (!waitRegistrationForCall || currentAccount->getState() == linphone::RegistrationState::Ok) {
qWarning() << "prepareTransfert not impolemented";
// CallModel::prepareTransfert(core->inviteAddressWithParams(address, params), prepareTransfertAddress);
} else {
qWarning() << "Waiting registration not implemented";
// QObject *context = new QObject();
// QObject::connect(
// CoreManager::getInstance()->getHandlers().get(), &CoreHandlers::registrationStateChanged, context,
// [address, core, params, currentAccount, prepareTransfertAddress, context](
// const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state) mutable {
// if (context && account == currentAccount && state == linphone::RegistrationState::Ok) {
// CallModel::prepareTransfert(core->inviteAddressWithParams(address, params),
// prepareTransfertAddress);
// context->deleteLater();
// context = nullptr;
// }
// });
}
} else qWarning() << "prepareTransfert not impolemented";
// CallModel::prepareTransfert(core->inviteAddressWithParams(address, params), prepareTransfertAddress);
*/
}

View file

@ -21,8 +21,10 @@
#ifndef TOOL_MODEL_H_
#define TOOL_MODEL_H_
#include "core/call/Call.hpp"
#include "tool/AbstractObject.hpp"
#include <QHash>
#include <QObject>
#include <linphone++/linphone.hh>
@ -37,6 +39,10 @@ public:
static QString getDisplayName(const std::shared_ptr<const linphone::Address> &address);
static QString getDisplayName(QString address);
static Call *startAudioCall(const QString &sipAddress,
const QString &prepareTransfertAddress = "",
const QHash<QString, QString> &headers = {});
private:
DECLARE_ABSTRACT_OBJECT
};

View file

@ -27,6 +27,7 @@
// =============================================================================
void LinphoneEnums::registerMetaTypes() {
qRegisterMetaType<LinphoneEnums::CallState>();
qRegisterMetaType<LinphoneEnums::CallStatus>();
qRegisterMetaType<LinphoneEnums::ChatMessageState>();
qRegisterMetaType<LinphoneEnums::ChatRoomState>();
@ -81,6 +82,13 @@ LinphoneEnums::ChatRoomState LinphoneEnums::fromLinphone(const linphone::ChatRoo
return static_cast<LinphoneEnums::ChatRoomState>(data);
}
linphone::Call::State LinphoneEnums::toLinphone(const LinphoneEnums::CallState &data) {
return static_cast<linphone::Call::State>(data);
}
LinphoneEnums::CallState LinphoneEnums::fromLinphone(const linphone::Call::State &data) {
return static_cast<LinphoneEnums::CallState>(data);
}
linphone::Call::Status LinphoneEnums::toLinphone(const LinphoneEnums::CallStatus &data) {
return static_cast<linphone::Call::Status>(data);
}
@ -88,6 +96,25 @@ LinphoneEnums::CallStatus LinphoneEnums::fromLinphone(const linphone::Call::Stat
return static_cast<LinphoneEnums::CallStatus>(data);
}
QString LinphoneEnums::toString(const LinphoneEnums::CallStatus &data) {
switch (data) {
case LinphoneEnums::CallStatus::Declined:
return "Declined";
case LinphoneEnums::CallStatus::Missed:
return "Missed";
case LinphoneEnums::CallStatus::Success:
return "Success";
case LinphoneEnums::CallStatus::Aborted:
return "Aborted";
case LinphoneEnums::CallStatus::EarlyAborted:
return "EarlyAborted";
case LinphoneEnums::CallStatus::AcceptedElsewhere:
return "AcceptedElsewhere";
case LinphoneEnums::CallStatus::DeclinedElsewhere:
return "DeclinedElsewhere";
}
}
linphone::Conference::Layout LinphoneEnums::toLinphone(const LinphoneEnums::ConferenceLayout &layout) {
if (layout != LinphoneEnums::ConferenceLayout::AudioOnly) return static_cast<linphone::Conference::Layout>(layout);
else return linphone::Conference::Layout::Grid; // Audio Only mode

View file

@ -30,6 +30,7 @@
namespace LinphoneEnums {
Q_NAMESPACE
Q_CLASSINFO("RegisterEnumClassesUnscoped", "false") // Avoid name clashes
void registerMetaTypes();
@ -115,6 +116,34 @@ Q_ENUM_NS(ChatRoomState)
linphone::ChatRoom::State toLinphone(const LinphoneEnums::ChatRoomState &data);
LinphoneEnums::ChatRoomState fromLinphone(const linphone::ChatRoom::State &data);
enum class CallState {
Idle = int(linphone::Call::State::Idle),
IncomingReceived = int(linphone::Call::State::IncomingReceived),
PushIncomingReceived = int(linphone::Call::State::PushIncomingReceived),
OutgoingInit = int(linphone::Call::State::OutgoingInit),
OutgoingProgress = int(linphone::Call::State::OutgoingProgress),
OutgoingRinging = int(linphone::Call::State::OutgoingRinging),
OutgoingEarlyMedia = int(linphone::Call::State::OutgoingEarlyMedia),
Connected = int(linphone::Call::State::Connected),
StreamsRunning = int(linphone::Call::State::StreamsRunning),
Pausing = int(linphone::Call::State::Pausing),
Paused = int(linphone::Call::State::Paused),
Resuming = int(linphone::Call::State::Resuming),
Referred = int(linphone::Call::State::Referred),
Error = int(linphone::Call::State::Error),
End = int(linphone::Call::State::End),
PausedByRemote = int(linphone::Call::State::PausedByRemote),
UpdatedByRemote = int(linphone::Call::State::UpdatedByRemote),
IncomingEarlyMedia = int(linphone::Call::State::IncomingEarlyMedia),
Updating = int(linphone::Call::State::Updating),
Released = int(linphone::Call::State::Released),
EarlyUpdatedByRemote = int(linphone::Call::State::EarlyUpdatedByRemote),
EarlyUpdating = int(linphone::Call::State::EarlyUpdating)
};
Q_ENUM_NS(CallState)
linphone::Call::State toLinphone(const LinphoneEnums::CallState &data);
LinphoneEnums::CallState fromLinphone(const linphone::Call::State &data);
enum class CallStatus {
Declined = int(linphone::Call::Status::Declined),
Missed = int(linphone::Call::Status::Missed),
@ -126,8 +155,9 @@ enum class CallStatus {
};
Q_ENUM_NS(CallStatus)
linphone::Call::Status toLinphone(const LinphoneEnums::CallStatus &capability);
LinphoneEnums::CallStatus fromLinphone(const linphone::Call::Status &capability);
linphone::Call::Status toLinphone(const LinphoneEnums::CallStatus &data);
LinphoneEnums::CallStatus fromLinphone(const linphone::Call::Status &data);
QString toString(const LinphoneEnums::CallStatus &data);
enum class ConferenceLayout {
Grid = int(linphone::Conference::Layout::Grid),
@ -227,7 +257,8 @@ LinphoneEnums::TransportType fromLinphone(const linphone::TransportType &type);
QString toString(const LinphoneEnums::TransportType &type);
void fromString(const QString &transportType, LinphoneEnums::TransportType *transport);
} // namespace LinphoneEnums
/*
Q_DECLARE_METATYPE(LinphoneEnums::CallState)
Q_DECLARE_METATYPE(LinphoneEnums::CallStatus)
Q_DECLARE_METATYPE(LinphoneEnums::ChatMessageState)
Q_DECLARE_METATYPE(LinphoneEnums::ChatRoomState)
@ -242,5 +273,5 @@ Q_DECLARE_METATYPE(LinphoneEnums::RecorderState)
Q_DECLARE_METATYPE(LinphoneEnums::RegistrationState)
Q_DECLARE_METATYPE(LinphoneEnums::TunnelMode)
Q_DECLARE_METATYPE(LinphoneEnums::TransportType)
*/
#endif

View file

@ -21,6 +21,7 @@
#include "Utils.hpp"
#include "core/App.hpp"
#include "model/call/CallModel.hpp"
#include "model/object/VariantObject.hpp"
#include "model/tool/ToolModel.hpp"
@ -43,7 +44,25 @@ VariantObject *Utils::getDisplayName(const QString &address) {
VariantObject *data = new VariantObject(address); // Scope : GUI
App::postModelAsync([coreObject = data->mCoreObject, address]() mutable {
QString displayName = ToolModel::getDisplayName(address);
emit coreObject->valueChanged(displayName);
coreObject->setValue(displayName);
});
return data;
}
VariantObject *Utils::startAudioCall(const QString &sipAddress,
const QString &prepareTransfertAddress,
const QHash<QString, QString> &headers) {
VariantObject *data = new VariantObject(QVariant()); // Scope : GUI
qDebug() << "Calling " << sipAddress;
App::postModelAsync([coreObject = data->mCoreObject, sipAddress, prepareTransfertAddress, headers]() mutable {
auto call = ToolModel::startAudioCall(sipAddress, prepareTransfertAddress, headers);
if (call && coreObject) {
call->moveToThread(App::getInstance()->thread());
coreObject->setValue(QVariant::fromValue(call));
// App::postCoreAsync([data, call]() { data->setValue(QVariant::fromValue(call)); });
// emit coreObject->valueChanged(call);
}
});
return data;
}

View file

@ -49,6 +49,9 @@ public:
}
Q_INVOKABLE static VariantObject *getDisplayName(const QString &address);
Q_INVOKABLE static VariantObject *startAudioCall(const QString &sipAddress,
const QString &prepareTransfertAddress = "",
const QHash<QString, QString> &headers = {});
static inline QString coreStringToAppString(const std::string &str) {
if (Constants::LinphoneLocaleEncoding == QString("UTF-8")) return QString::fromStdString(str);

View file

@ -8,7 +8,12 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Item/Carousel.qml
view/Item/CheckBox.qml
view/Item/ComboBox.qml
view/Item/DesktopPopup.qml
view/Item/DigitInput.qml
view/Item/Notification/Notification.qml
view/Item/Notification/NotificationReceivedCall.qml
view/Item/PhoneNumberComboBox.qml
view/Item/PhoneNumberInput.qml
view/Item/RadioButton.qml
@ -35,6 +40,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
# Prototypes
view/Prototype/PhoneNumberPrototype.qml
view/Prototype/AccountsPrototype.qml
view/Prototype/CallPrototype.qml
)
list(APPEND _LINPHONEAPP_QML_SINGLETONS

View file

@ -0,0 +1,187 @@
import QtQuick 2.7
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import Qt.labs.platform 1.0
// =============================================================================
Window {
id: mainItem
// ---------------------------------------------------------------------------
property bool requestActivate: false
//property int flags: Qt.SplashScreen
default property alias _content: content.data
property bool _isOpen: false
signal isOpened()
signal isClosed()
signal dataChanged()
on_ContentChanged: dataChanged(_content)
// ---------------------------------------------------------------------------
function open () {
_isOpen = true;
isOpened();
}
/*
function close () {
_isOpen = false
isClosed()
}
*/
// ---------------------------------------------------------------------------
objectName: '__internalWindow'
property bool isFrameLess : false;
property bool showAsTool : false
// Don't use Popup for flags : it could lead to error in geometry. On Mac, Using Tool ensure to have the Window on Top and fullscreen independant
flags: Qt.BypassWindowManagerHint | (showAsTool?Qt.Tool:Qt.WindowStaysOnTopHint) | Qt.Window | Qt.FramelessWindowHint;
opacity: 1.0
height: _content[0] != null ? _content[0].height : 0
width: _content[0] != null ? _content[0].width : 0
visible:true
Item {
id: content
anchors.fill:parent
property var $parent: mainItem
}
// ---------------------------------------------------------------------------
/*
states: State {
name: 'opening'
when: _isOpen
PropertyChanges {
opacity: 1.0
target: window
}
}
transitions: [
Transition {
from: ''
to: 'opening'
ScriptAction {
script: {
if (wrapper.requestActivate) {
window.requestActivate()
}
}
}
},
Transition {
from: '*'
to: ''
ScriptAction {
script: window.close()
}
}
]
*/
}
/*
Item {
id: wrapper
objectName: '__internalWrapper'
// ---------------------------------------------------------------------------
property alias popupX: window.x
property alias popupY: window.y
property bool requestActivate: false
property int flags: Qt.SplashScreen
readonly property alias popupWidth: window.width
readonly property alias popupHeight: window.height
default property alias _content: content.data
property bool _isOpen: false
signal isOpened()
signal isClosed()
signal dataChanged()
on_ContentChanged: dataChanged(_content)
// ---------------------------------------------------------------------------
function open () {
_isOpen = true;
isOpened();
}
function close () {
_isOpen = false
isClosed()
}
// ---------------------------------------------------------------------------
// No size, no position.
height: 0
width: 0
visible:true
Window {
id: window
objectName: '__internalWindow'
property bool isFrameLess : false;
property bool showAsTool : false
// Don't use Popup for flags : it could lead to error in geometry. On Mac, Using Tool ensure to have the Window on Top and fullscreen independant
flags: Qt.BypassWindowManagerHint | (showAsTool?Qt.Tool:Qt.WindowStaysOnTopHint) | Qt.Window | Qt.FramelessWindowHint;
onXChanged: console.log(x)
opacity: 1.0
height: _content[0] != null ? _content[0].height : 0
width: _content[0] != null ? _content[0].width : 0
visible:true
Item {
id: content
anchors.fill:parent
property var $parent: wrapper
}
}
// ---------------------------------------------------------------------------
states: State {
name: 'opening'
when: _isOpen
PropertyChanges {
opacity: 1.0
target: window
}
}
transitions: [
Transition {
from: ''
to: 'opening'
ScriptAction {
script: {
if (wrapper.requestActivate) {
window.requestActivate()
}
}
}
},
Transition {
from: '*'
to: ''
ScriptAction {
script: window.close()
}
}
]
}
*/

View file

@ -0,0 +1,57 @@
import QtQuick 2.7
import Linphone
// =============================================================================
DesktopPopup {
id: notification
property var notificationData: ({
timelineModel : null
})
property int overrodeHeight
default property alias _content: content.data
signal deleteNotification (var notification)
// Use as an intermediate between signal/slot without propagate the notification var : last signal parameter will be the last notification instance
function deleteNotificationSlot(){
deleteNotification(notification)
}
function _close (cb) {
if (cb) {
cb()
}
deleteNotificationSlot();
}
Rectangle {
color: "#FFFFFF"
height: overrodeHeight || 120
width: 300
border {
color: "#A1A1A1"
width: 1
}
Item {
id: content
anchors.fill: parent
}
Image {
id: iconSign
anchors {
left: parent.left
top: parent.top
}
}
}
}

View file

@ -0,0 +1,54 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import Linphone
// =============================================================================
Notification {
id: notification
// ---------------------------------------------------------------------------
readonly property var call: notificationData && notificationData.call
property var state: call.state
onStateChanged:{
if(state != LinphoneEnums.CallState.IncomingReceived){
close()
}
}
// ---------------------------------------------------------------------------
ColumnLayout {
anchors.fill: parent
anchors.leftMargin: 15
anchors.rightMargin: 15
anchors.bottomMargin:15
spacing: 0
// ---------------------------------------------------------------------
// Action buttons.
// ---------------------------------------------------------------------
RowLayout {
Layout.fillHeight: true
Layout.fillWidth: true
Button {
text: 'Accept'
Layout.rightMargin: 20
onClicked: {
notification.call.lAccept()
}
}
Item{
Layout.fillWidth: true
Layout.fillHeight: true
}
Button {
text: 'Reject'
Layout.rightMargin: 20
onClicked: {
notification.call.lDecline()
}
}
}
}
}

View file

@ -0,0 +1,80 @@
import QtQuick 2.15
import QtQuick.Layouts 1.0
import QtQuick.Controls as Control
import Linphone
import UtilsCpp 1.0
// Snippet
Window{
id: mainItem
height: 400
width: 800
onWidthChanged: console.log(width)
property var callVarObject
property var call: callVarObject ? callVarObject.value : null
property var callState: call && call.state
onCallStateChanged: console.log("State:" +callState)
visible: true
onCallChanged: console.log('New Call:' +call)
ColumnLayout{
anchors.fill: parent
RowLayout {
Layout.fillWidth: true
LoginForm{
}
Rectangle{
Layout.preferredWidth: 50
Layout.preferredHeight: 50
color: LoginPageCpp.registrationState === LinphoneEnums.RegistrationState.Ok
? 'green'
: LoginPageCpp.registrationState === LinphoneEnums.RegistrationState.Failed || LoginPageCpp.registrationState === LinphoneEnums.RegistrationState.None
? 'red'
: 'orange'
}
TextInput {
id: usernameToCall
label: "Username to call"
textInputWidth: 250
}
Button{
text: 'Call'
onClicked: {
mainItem.callVarObject = UtilsCpp.startAudioCall(usernameToCall.inputText + "@sip.linphone.org")
}
}
}
Rectangle{
Layout.fillWidth: true
Layout.preferredHeight: 50
color: call
? call.state === LinphoneEnums.CallState.StreamsRunning
? 'green'
: call.state === LinphoneEnums.CallState.Released
? 'pink'
: 'orange'
: 'red'
Rectangle{
anchors.centerIn: parent
color: 'white'
width: stateText.contentWidth
height: stateText.contentHeight
Text{
id: stateText
text: "State:"+(mainItem.callState ? mainItem.callState : 'None')
}
}
}
Text{
id: errorMessageText
text: mainItem.call ? mainItem.call.lastErrorMessage : ''
color: 'red'
}
Item{
Layout.fillHeight: true
Layout.fillWidth: true
}
}
}

@ -1 +1 @@
Subproject commit 8756a37ad10399a0c27d32590a0d1cc87ea97c2e
Subproject commit aaeaad94a6e63f182f50318ed1a209c83b152d73