Upgrade to SDK 5.4.11

This commit is contained in:
Julien Wadel 2025-04-29 15:49:06 +02:00
parent 2fa9b68116
commit 6e2c956b70
7 changed files with 443 additions and 428 deletions

View file

@ -163,8 +163,8 @@ static void cliInitiateConference(QHash<QString, QString> &args) {
}
if (!account->getParams()->getIdentityAddress()->weakEqual(address)) {
qWarning() << QStringLiteral("Received different sip address from identity : `%1 != %2`.")
.arg(Utils::coreStringToAppString(account->getParams()->getIdentityAddress()->asString()))
.arg(Utils::coreStringToAppString(address->asString()));
.arg(Utils::coreStringToAppString(account->getParams()->getIdentityAddress()->asString()))
.arg(Utils::coreStringToAppString(address->asString()));
return;
}
@ -173,24 +173,26 @@ static void cliInitiateConference(QHash<QString, QString> &args) {
auto updateCallsWindow = []() {
QQuickWindow *callsWindow = App::getInstance()->getCallsWindow();
if (!callsWindow) return;
if (!callsWindow)
return;
// TODO: Set the view to the "waiting call view".
if (CoreManager::getInstance()->getSettingsModel()->getKeepCallsWindowInBackground()) {
if (!callsWindow->isVisible()) callsWindow->showMinimized();
} else App::smartShowWindow(callsWindow);
if (!callsWindow->isVisible())
callsWindow->showMinimized();
} else
App::smartShowWindow(callsWindow);
};
if (conference) {
qInfo() << QStringLiteral("Conference `%1` already exists.")
.arg(Utils::coreStringToAppString(conference->getConferenceAddress()->asString()));
qInfo() << QStringLiteral("Conference `%1` already exists.").arg(Utils::coreStringToAppString(conference->getConferenceAddress()->asString()));
updateCallsWindow();
return;
}
qInfo() << QStringLiteral("Create conference with id: `%1`.").arg(id);
auto confParameters = core->createConferenceParams(conference);
confParameters->enableVideo(false); // Video is not yet fully supported by the application in conference
confParameters->enableVideo(false);// Video is not yet fully supported by the application in conference
conference = core->createConferenceWithParams(confParameters);
if (conference->enter() == -1) {

View file

@ -39,8 +39,6 @@
#include "CallsListModel.hpp"
// =============================================================================
using namespace std;
@ -48,132 +46,143 @@ using namespace std;
namespace {
// Delay before removing call in ms.
constexpr int DelayBeforeRemoveCall = 6000;
}
} // namespace
static inline int findCallIndex (QList<QSharedPointer<QObject>> &list, const shared_ptr<linphone::Call> &call) {
static inline int findCallIndex(QList<QSharedPointer<QObject>> &list, const shared_ptr<linphone::Call> &call) {
auto it = find_if(list.begin(), list.end(), [call](QSharedPointer<QObject> callModel) {
return call == callModel.objectCast<CallModel>()->getCall();
return call == callModel.objectCast<CallModel>()->getCall();
});
return it == list.end() ? -1 : int(distance(list.begin(), it));
}
static inline int findCallIndex (QList<QSharedPointer<QObject>> &list, const CallModel &callModel) {
static inline int findCallIndex(QList<QSharedPointer<QObject>> &list, const CallModel &callModel) {
return ::findCallIndex(list, callModel.getCall());
}
// -----------------------------------------------------------------------------
CallsListModel::CallsListModel (QObject *parent) : ProxyListModel(parent) {
CallsListModel::CallsListModel(QObject *parent) : ProxyListModel(parent) {
mCoreHandlers = CoreManager::getInstance()->getHandlers();
QObject::connect(
mCoreHandlers.get(), &CoreHandlers::callStateChanged,
this, &CallsListModel::handleCallStateChanged
);
QObject::connect(mCoreHandlers.get(), &CoreHandlers::callStateChanged, this,
&CallsListModel::handleCallStateChanged);
connect(this, &CallsListModel::countChanged, this, &CallsListModel::canMergeCallsChanged);
}
CallModel *CallsListModel::findCallModelFromPeerAddress (const QString &peerAddress) const {
CallModel *CallsListModel::findCallModelFromPeerAddress(const QString &peerAddress) const {
std::shared_ptr<linphone::Address> address = Utils::interpretUrl(peerAddress);
auto it = find_if(mList.begin(), mList.end(), [address](QSharedPointer<QObject> callModel) {
return callModel.objectCast<CallModel>()->getRemoteAddress()->weakEqual(address);
return callModel.objectCast<CallModel>()->getRemoteAddress()->weakEqual(address);
});
return it != mList.end() ? it->objectCast<CallModel>().get() : nullptr;
}
// -----------------------------------------------------------------------------
void CallsListModel::askForTransfer (CallModel *callModel) {
void CallsListModel::askForTransfer(CallModel *callModel) {
emit callTransferAsked(callModel);
}
void CallsListModel::askForAttendedTransfer (CallModel *callModel) {
void CallsListModel::askForAttendedTransfer(CallModel *callModel) {
emit callAttendedTransferAsked(callModel);
}
// -----------------------------------------------------------------------------
void CallsListModel::launchAudioCall (const QString &sipAddress, const QString& prepareTransfertAddress, const QHash<QString, QString> &headers) const {
void CallsListModel::launchAudioCall(const QString &sipAddress,
const QString &prepareTransfertAddress,
const QHash<QString, QString> &headers) const {
CoreManager::getInstance()->getSettingsModel()->stopCaptureGraphs();
CoreManager::getInstance()->getTimelineListModel()->mAutoSelectAfterCreation = true;
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Address> address = Utils::interpretUrl(sipAddress);
if (!address){
if (!address) {
qCritical() << "The calling address is not an interpretable SIP address: " << sipAddress;
return;
}
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()));
params->addCustomHeader(Utils::appStringToCoreString(iterator.key()),
Utils::appStringToCoreString(iterator.value()));
}
if(core->getDefaultAccount())
params->setAccount(core->getDefaultAccount());
if (core->getDefaultAccount()) params->setAccount(core->getDefaultAccount());
CallModel::setRecordFile(params, Utils::coreStringToAppString(address->getUsername()));
shared_ptr<linphone::Account> currentAccount = core->getDefaultAccount();
if(currentAccount){
if(!CoreManager::getInstance()->getSettingsModel()->getWaitRegistrationForCall() || currentAccount->getState() == linphone::RegistrationState::Ok)
if (currentAccount) {
if (!CoreManager::getInstance()->getSettingsModel()->getWaitRegistrationForCall() ||
currentAccount->getState() == linphone::RegistrationState::Ok)
CallModel::prepareTransfert(core->inviteAddressWithParams(address, params), prepareTransfertAddress);
else{
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 {
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
CallModel::prepareTransfert(core->inviteAddressWithParams(address, params), prepareTransfertAddress);
} else CallModel::prepareTransfert(core->inviteAddressWithParams(address, params), prepareTransfertAddress);
}
void CallsListModel::launchSecureAudioCall (const QString &sipAddress, LinphoneEnums::MediaEncryption encryption, const QHash<QString, QString> &headers, const QString& prepareTransfertAddress) const {
void CallsListModel::launchSecureAudioCall(const QString &sipAddress,
LinphoneEnums::MediaEncryption encryption,
const QHash<QString, QString> &headers,
const QString &prepareTransfertAddress) const {
CoreManager::getInstance()->getSettingsModel()->stopCaptureGraphs();
CoreManager::getInstance()->getTimelineListModel()->mAutoSelectAfterCreation = true;
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Address> address = Utils::interpretUrl(sipAddress);
if (!address)
return;
if (!address) return;
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()));
params->addCustomHeader(Utils::appStringToCoreString(iterator.key()),
Utils::appStringToCoreString(iterator.value()));
}
if(core->getDefaultAccount())
params->setAccount(core->getDefaultAccount());
if (core->getDefaultAccount()) params->setAccount(core->getDefaultAccount());
CallModel::setRecordFile(params, Utils::coreStringToAppString(address->getUsername()));
shared_ptr<linphone::Account> currentAccount = core->getDefaultAccount();
params->setMediaEncryption(LinphoneEnums::toLinphone(encryption));
if(currentAccount){
if(!CoreManager::getInstance()->getSettingsModel()->getWaitRegistrationForCall() || currentAccount->getState() == linphone::RegistrationState::Ok)
if (currentAccount) {
if (!CoreManager::getInstance()->getSettingsModel()->getWaitRegistrationForCall() ||
currentAccount->getState() == linphone::RegistrationState::Ok)
CallModel::prepareTransfert(core->inviteAddressWithParams(address, params), prepareTransfertAddress);
else{
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 {
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
CallModel::prepareTransfert(core->inviteAddressWithParams(address, params), prepareTransfertAddress);
} else CallModel::prepareTransfert(core->inviteAddressWithParams(address, params), prepareTransfertAddress);
}
void CallsListModel::launchVideoCall (const QString &sipAddress, const QString& prepareTransfertAddress, const bool& autoSelectAfterCreation, QVariantMap options) const {
void CallsListModel::launchVideoCall(const QString &sipAddress,
const QString &prepareTransfertAddress,
const bool &autoSelectAfterCreation,
QVariantMap options) const {
CoreManager::getInstance()->getSettingsModel()->stopCaptureGraphs();
CoreManager::getInstance()->getTimelineListModel()->mAutoSelectAfterCreation = autoSelectAfterCreation;
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
@ -182,16 +191,18 @@ void CallsListModel::launchVideoCall (const QString &sipAddress, const QString&
launchAudioCall(sipAddress, prepareTransfertAddress, {});
return;
}
shared_ptr<linphone::Address> address = Utils::interpretUrl(sipAddress);
if (!address)
return;
shared_ptr<linphone::CallParams> params = core->createCallParams(nullptr);
auto layout = options.contains("layout") ? LinphoneEnums::toLinphone((LinphoneEnums::ConferenceLayout)options["layout"].toInt()) : LinphoneEnums::toLinphone(CoreManager::getInstance()->getSettingsModel()->getVideoConferenceLayout());
bool enableMicro =options.contains("micro") ? options["micro"].toBool() : true;
shared_ptr<linphone::Address> address = Utils::interpretUrl(sipAddress);
if (!address) return;
shared_ptr<linphone::CallParams> params = core->createCallParams(nullptr);
auto layout =
options.contains("layout")
? LinphoneEnums::toLinphone((LinphoneEnums::ConferenceLayout)options["layout"].toInt())
: LinphoneEnums::toLinphone(CoreManager::getInstance()->getSettingsModel()->getVideoConferenceLayout());
bool enableMicro = options.contains("micro") ? options["micro"].toBool() : true;
bool enableVideo = options.contains("video") ? options["video"].toBool() : true;
bool enableCamera = options.contains("camera") ? options["camera"].toBool() : true;
bool enableSpeaker = options.contains("audio") ? options["audio"].toBool() : true;
@ -200,44 +211,42 @@ void CallsListModel::launchVideoCall (const QString &sipAddress, const QString&
params->enableMic(enableMicro);
params->enableVideo(enableVideo);
params->setVideoDirection(enableCamera ? linphone::MediaDirection::SendRecv : linphone::MediaDirection::RecvOnly);
if(core->getDefaultAccount())
params->setAccount(core->getDefaultAccount());
if (core->getDefaultAccount()) params->setAccount(core->getDefaultAccount());
CallModel::setRecordFile(params, Utils::coreStringToAppString(address->getUsername()));
auto call = core->inviteAddressWithParams(address, params);
if(!call)
qWarning() << "Cannot initiate call. Maybe another one is currently done: delay the call.";
else{
if (!call) qWarning() << "Cannot initiate call. Maybe another one is currently done: delay the call.";
else {
call->setSpeakerMuted(!enableSpeaker);
qInfo() << "Launch " << (enableVideo ? "video" : "audio") << " call; camera: " << enableCamera<< " speaker:" << enableSpeaker << ", micro:" << params->micEnabled() << ", layout:" << (int)layout;
qInfo() << "Launch " << (enableVideo ? "video" : "audio") << " call; camera: " << enableCamera
<< " speaker:" << enableSpeaker << ", micro:" << params->micEnabled() << ", layout:" << (int)layout;
CallModel::prepareTransfert(call, prepareTransfertAddress);
}
}
QVariantMap CallsListModel::launchChat(const QString &sipAddress, const int& securityLevel) const{
QVariantMap CallsListModel::launchChat(const QString &sipAddress, const int &securityLevel) const {
QVariantList participants;
participants << sipAddress;
return createChatRoom("", securityLevel, participants, true);
}
ChatRoomModel* CallsListModel::createChat (const QString &participantAddress) const{
ChatRoomModel *CallsListModel::createChat(const QString &participantAddress) const {
CoreManager::getInstance()->getTimelineListModel()->mAutoSelectAfterCreation = true;
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Address> address = Utils::interpretUrl(participantAddress);
if (!address)
return nullptr;
if (!address) return nullptr;
std::shared_ptr<linphone::ChatRoomParams> params = core->createDefaultChatRoomParams();
std::list <shared_ptr<linphone::Address> > participants;
std::list<shared_ptr<linphone::Address>> participants;
std::shared_ptr<const linphone::Address> localAddress;
participants.push_back(address);
params->setBackend(linphone::ChatRoom::Backend::Basic);
qInfo() << "Create ChatRoom with " <<participantAddress;
qInfo() << "Create ChatRoom with " << participantAddress;
std::shared_ptr<linphone::ChatRoom> chatRoom = core->createChatRoom(params, localAddress, participants);
if( chatRoom != nullptr){
if (chatRoom != nullptr) {
auto timelineList = CoreManager::getInstance()->getTimelineListModel();
auto timeline = timelineList->getTimeline(chatRoom, true);
return timeline->getChatRoomModel();
@ -245,312 +254,303 @@ ChatRoomModel* CallsListModel::createChat (const QString &participantAddress) co
return nullptr;
}
ChatRoomModel* CallsListModel::createChat (CallModel * model){
if(model){
ChatRoomModel *CallsListModel::createChat(CallModel *model) {
if (model) {
return model->getChatRoomModel();
}
return nullptr;
}
bool CallsListModel::createSecureChat (const QString& subject, const QString &participantAddress) const{
bool CallsListModel::createSecureChat(const QString &subject, const QString &participantAddress) const {
CoreManager::getInstance()->getTimelineListModel()->mAutoSelectAfterCreation = true;
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Address> address = Utils::interpretUrl(participantAddress);
if (!address)
return false;
if (!address) return false;
std::shared_ptr<linphone::ChatRoomParams> params = core->createDefaultChatRoomParams();
std::list <shared_ptr<linphone::Address> > participants;
std::list<shared_ptr<linphone::Address>> participants;
std::shared_ptr<const linphone::Address> localAddress;
participants.push_back(address);
params->enableEncryption(true);
params->setSubject(Utils::appStringToCoreString(subject));
params->enableEncryption(true);
params->enableGroup(true);
qInfo() << "Create secure ChatRoom: " << subject << ", from " << QString::fromStdString(localAddress->asString()) << " and with " <<participantAddress;;
qInfo() << "Create secure ChatRoom: " << subject << ", from " << QString::fromStdString(localAddress->asString())
<< " and with " << participantAddress;
;
std::shared_ptr<linphone::ChatRoom> chatRoom = core->createChatRoom(params, localAddress, participants);
// Still needed?
// if( chatRoom != nullptr){
// auto timelineList = CoreManager::getInstance()->getTimelineListModel();
// timelineList->update();
// auto timeline = timelineList->getTimeline(chatRoom, false);
// if(!timeline){
// timeline = timelineList->getTimeline(chatRoom, true);
// timelineList->add(timeline);
// }
// return timeline->getChatRoomModel();
// }
// Still needed?
// if( chatRoom != nullptr){
// auto timelineList = CoreManager::getInstance()->getTimelineListModel();
// timelineList->update();
// auto timeline = timelineList->getTimeline(chatRoom, false);
// if(!timeline){
// timeline = timelineList->getTimeline(chatRoom, true);
// timelineList->add(timeline);
// }
// return timeline->getChatRoomModel();
// }
return chatRoom != nullptr;
}
// Created, timeline that can be used
QVariantMap CallsListModel::createChatRoom(const QString& subject, const int& securityLevel, const QVariantList& participants, const bool& selectAfterCreation) const{
QVariantMap CallsListModel::createChatRoom(const QString &subject,
const int &securityLevel,
const QVariantList &participants,
const bool &selectAfterCreation) const {
return createChatRoom(subject, securityLevel, nullptr, participants, selectAfterCreation);
}
QVariantMap CallsListModel::createChatRoom(const QString& subject, const int& securityLevel, std::shared_ptr<linphone::Address> localAddress, const QVariantList& participants, const bool& selectAfterCreation) const{
QVariantMap CallsListModel::createChatRoom(const QString &subject,
const int &securityLevel,
std::shared_ptr<linphone::Address> localAddress,
const QVariantList &participants,
const bool &selectAfterCreation) const {
CoreManager::getInstance()->getTimelineListModel()->mAutoSelectAfterCreation = selectAfterCreation;
QVariantMap result;
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
std::shared_ptr<linphone::ChatRoom> chatRoom;
QList< std::shared_ptr<linphone::Address>> admins;
QList<std::shared_ptr<linphone::Address>> admins;
QSharedPointer<TimelineModel> timeline;
auto timelineList = CoreManager::getInstance()->getTimelineListModel();
QString localAddressStr = (localAddress ? Utils::coreStringToAppString(localAddress->asStringUriOnly()) : "local");
qInfo() << "Create ChatRoom: " << subject << " at " << securityLevel << " security, from " << localAddressStr << " and with " << participants;
qInfo() << "Create ChatRoom: " << subject << " at " << securityLevel << " security, from " << localAddressStr
<< " and with " << participants;
std::shared_ptr<linphone::ChatRoomParams> params = core->createDefaultChatRoomParams();
std::list <shared_ptr<linphone::Address> > chatRoomParticipants;
for(auto p : participants){
ParticipantModel* participant = p.value<ParticipantModel*>();
std::list<shared_ptr<linphone::Address>> chatRoomParticipants;
for (auto p : participants) {
ParticipantModel *participant = p.value<ParticipantModel *>();
std::shared_ptr<linphone::Address> address;
if(participant) {
if (participant) {
address = Utils::interpretUrl(participant->getSipAddress());
if(participant->getAdminStatus())
admins << address;
}else{
if (participant->getAdminStatus()) admins << address;
} else {
QString participant = p.toString();
if( participant != "")
address = Utils::interpretUrl(participant);
if (participant != "") address = Utils::interpretUrl(participant);
}
if( address)
chatRoomParticipants.push_back( address );
if (address) chatRoomParticipants.push_back(address);
else
qWarning() << "Failed to add participant to conference, bad address : " << (participant ? participant->getSipAddress() : p.toString());
qWarning() << "Failed to add participant to conference, bad address : "
<< (participant ? participant->getSipAddress() : p.toString());
}
params->enableEncryption(securityLevel>0);
if( securityLevel<=0)
params->setBackend(linphone::ChatRoom::Backend::Basic);
params->enableGroup( subject!="" );
if(chatRoomParticipants.size() > 0) {
if(!params->groupEnabled()) {// Chat room is one-one : check if it is already exist with empty or dummy subject
chatRoom = core->searchChatRoom(params, localAddress
, nullptr
, chatRoomParticipants);
if(chatRoom && ChatRoomModel::isTerminated(chatRoom))
chatRoom = nullptr;
params->setSubject(subject != ""?Utils::appStringToCoreString(subject):"Dummy Subject");
if(!chatRoom)
chatRoom = core->searchChatRoom(params, localAddress
, nullptr
, chatRoomParticipants);
if(chatRoom && ChatRoomModel::isTerminated(chatRoom))
chatRoom = nullptr;
}else
params->setSubject(subject != ""?Utils::appStringToCoreString(subject):"Dummy Subject");
if( !chatRoom) {
params->enableEncryption(securityLevel > 0);
if (securityLevel <= 0) params->setBackend(linphone::ChatRoom::Backend::Basic);
params->enableGroup(subject != "");
if (chatRoomParticipants.size() > 0) {
if (!params
->groupEnabled()) { // Chat room is one-one : check if it is already exist with empty or dummy subject
chatRoom = core->searchChatRoom(params, localAddress, nullptr, chatRoomParticipants);
if (chatRoom && ChatRoomModel::isTerminated(chatRoom)) chatRoom = nullptr;
params->setSubject(subject != "" ? Utils::appStringToCoreString(subject) : "Dummy Subject");
if (!chatRoom) chatRoom = core->searchChatRoom(params, localAddress, nullptr, chatRoomParticipants);
if (chatRoom && ChatRoomModel::isTerminated(chatRoom)) chatRoom = nullptr;
} else params->setSubject(subject != "" ? Utils::appStringToCoreString(subject) : "Dummy Subject");
if (!chatRoom) {
chatRoom = core->createChatRoom(params, localAddress, chatRoomParticipants);
if(chatRoom != nullptr && admins.size() > 0){
if (chatRoom != nullptr && admins.size() > 0) {
auto initializer = ChatRoomInitializer::create(chatRoom);
initializer->setAdminsData(admins);
ChatRoomInitializer::start(initializer);
}
timeline = timelineList->getTimeline(chatRoom, true);
}else{
if(admins.size() > 0){
} else {
if (admins.size() > 0) {
ChatRoomInitializer::create(chatRoom)->setAdmins(admins);
}
timeline = timelineList->getTimeline(chatRoom, true);
}
if(timeline){
if (timeline) {
CoreManager::getInstance()->getTimelineListModel()->mAutoSelectAfterCreation = false;
result["chatRoomModel"] = QVariant::fromValue(timeline->getChatRoomModel());
if(selectAfterCreation) {// The timeline here will not receive the first creation event. Set Selected if needed
if (selectAfterCreation) { // The timeline here will not receive the first creation event. Set Selected if
// needed
timeline->delaySelected();
}
}
}
if( !chatRoom)
qWarning() << "Chat room cannot be created";
else if(securityLevel > 0) {
if (!chatRoom) qWarning() << "Chat room cannot be created";
else if (securityLevel > 0) {
int ephemeralTime = CoreManager::getInstance()->getSettingsModel()->getCreateEphemeralChatRooms();
if( ephemeralTime>0){
if (ephemeralTime > 0) {
chatRoom->setEphemeralLifetime(ephemeralTime);
chatRoom->enableEphemeral(true);
}
}
result["created"] = (chatRoom != nullptr);
return result;
}
void CallsListModel::prepareConferenceCall(ConferenceInfoModel * model){
if(model->getConferenceInfoState() != LinphoneEnums::ConferenceInfoStateCancelled) {
void CallsListModel::prepareConferenceCall(ConferenceInfoModel *model) {
if (model->getConferenceInfoState() != LinphoneEnums::ConferenceInfoStateCancelled) {
auto app = App::getInstance();
app->smartShowWindow(app->getCallsWindow());
emit callConferenceAsked(model);
}
}
int CallsListModel::addAllToConference(){
int CallsListModel::addAllToConference() {
return CoreManager::getInstance()->getCore()->addAllToConference();
}
void CallsListModel::mergeAll(){
void CallsListModel::mergeAll() {
auto core = CoreManager::getInstance()->getCore();
auto currentCalls = CoreManager::getInstance()->getCore()->getCalls();
shared_ptr<linphone::Conference> conference = core->getConference();
shared_ptr<linphone::Conference> conference;
// Search a managable conference from calls
if(!conference){
for(auto call : currentCalls){
auto dbConference = call->getConference();
if(dbConference && dbConference->getMe()->isAdmin()){
conference = dbConference;
break;
}
for (auto call : currentCalls) {
auto dbConference = call->getConference();
if (dbConference && dbConference->getMe()->isAdmin()) {
conference = dbConference;
break;
}
}
auto currentCall = CoreManager::getInstance()->getCore()->getCurrentCall();
bool enablingVideo = false;
if( currentCall )
enablingVideo = currentCall->getCurrentParams()->videoEnabled();
if(!conference){
if (currentCall) enablingVideo = currentCall->getCurrentParams()->videoEnabled();
if (!conference) {
auto parameters = core->createConferenceParams(conference);
if(!CoreManager::getInstance()->getSettingsModel()->getVideoConferenceEnabled()) {
if (!CoreManager::getInstance()->getSettingsModel()->getVideoConferenceEnabled()) {
parameters->enableVideo(false);
parameters->setConferenceFactoryAddress(nullptr);// Do a local conference
parameters->setConferenceFactoryAddress(nullptr); // Do a local conference
parameters->setSubject("Local meeting");
}else{
} else {
parameters->enableVideo(enablingVideo);
parameters->setSubject("Meeting");
}
conference = core->createConferenceWithParams(parameters);
}
list<shared_ptr<linphone::Address>> allLinphoneAddresses;
list<shared_ptr<linphone::Address>> newCalls;
list<shared_ptr<linphone::Call>> runningCallsToAdd;
for(auto call : currentCalls){
if(!call->getConference()){
for (auto call : currentCalls) {
if (!call->getConference()) {
runningCallsToAdd.push_back(call);
}
}
// 1) Add running calls
if( runningCallsToAdd.size() > 0){
// 1) Add running calls
if (runningCallsToAdd.size() > 0) {
conference->addParticipants(runningCallsToAdd);
}
/*
// 2) Put in pause and remove all calls that are not in the conference list
for(const auto &call : CoreManager::getInstance()->getCore()->getCalls()){
const std::string callAddress = call->getRemoteAddress()->asStringUriOnly();
auto address = allLinphoneAddresses.begin();
while(address != allLinphoneAddresses.end() && (*address)->asStringUriOnly() != callAddress)
++address;
if(address == allLinphoneAddresses.end()){// Not in conference list : put in pause and remove it from conference if it's the case
if( call->getParams()->getLocalConferenceMode() ){// Remove conference if it is not yet requested
CoreManager::getInstance()->getCore()->removeFromConference(call);
}else
call->pause();
}
}*/
/*
// 2) Put in pause and remove all calls that are not in the conference list
for(const auto &call : CoreManager::getInstance()->getCore()->getCalls()){
const std::string callAddress = call->getRemoteAddress()->asStringUriOnly();
auto address = allLinphoneAddresses.begin();
while(address != allLinphoneAddresses.end() && (*address)->asStringUriOnly() != callAddress)
++address;
if(address == allLinphoneAddresses.end()){// Not in conference list : put in pause and remove it from
conference if it's the case if( call->getParams()->getLocalConferenceMode() ){// Remove conference if it is not yet
requested CoreManager::getInstance()->getCore()->removeFromConference(call); }else call->pause();
}
}*/
}
// -----------------------------------------------------------------------------
int CallsListModel::getRunningCallsNumber () const {
int CallsListModel::getRunningCallsNumber() const {
return CoreManager::getInstance()->getCore()->getCallsNb();
}
bool CallsListModel::canMergeCalls()const{
bool CallsListModel::canMergeCalls() const {
auto calls = CoreManager::getInstance()->getCore()->getCalls();
bool mergableConference = false;
int mergableCalls = 0;
bool mergable = false;
for(auto itCall = calls.begin(); !mergable && itCall != calls.end() ; ++itCall ) {
for (auto itCall = calls.begin(); !mergable && itCall != calls.end(); ++itCall) {
auto conference = (*itCall)->getConference();
if(conference){
if( !mergableConference )
mergableConference = (conference && conference->getMe()->isAdmin());
}else{
if (conference) {
if (!mergableConference) mergableConference = (conference && conference->getMe()->isAdmin());
} else {
++mergableCalls;
}
mergable = (mergableConference && mergableCalls>0) // A call can be merged into the conference
|| mergableCalls>1;// 2 calls can be merged
mergable = (mergableConference && mergableCalls > 0) // A call can be merged into the conference
|| mergableCalls > 1; // 2 calls can be merged
}
return mergable;
}
void CallsListModel::terminateAllCalls () const {
void CallsListModel::terminateAllCalls() const {
CoreManager::getInstance()->getCore()->terminateAllCalls();
}
void CallsListModel::terminateCall (const QString& sipAddress) const{
void CallsListModel::terminateCall(const QString &sipAddress) const {
auto coreManager = CoreManager::getInstance();
shared_ptr<linphone::Address> address = Utils::interpretUrl(sipAddress);
if (!address)
qWarning() << "Cannot terminate Call. The address cannot be parsed : " << sipAddress;
else{
if (!address) qWarning() << "Cannot terminate Call. The address cannot be parsed : " << sipAddress;
else {
std::shared_ptr<linphone::Call> call = coreManager->getCore()->getCallByRemoteAddress2(address);
if( call){
if (call) {
coreManager->lockVideoRender();
call->terminate();
coreManager->unlockVideoRender();
}else{
} else {
qWarning() << "Cannot terminate call as it doesn't exist : " << sipAddress;
}
}
}
QSharedPointer<CallModel> CallsListModel::getLastCall(bool incoming) const{
QSharedPointer<CallModel> CallsListModel::getLastCall(bool incoming) const {
QSharedPointer<CallModel> lastCall = nullptr;
time_t lastTime = 0;
auto item = mList.rbegin();
while(item != mList.rend() && !lastCall) {
while (item != mList.rend() && !lastCall) {
auto call = item->objectCast<CallModel>();
if(!incoming || call->getStatus() == CallModel::CallStatusIncoming) {
if (!incoming || call->getStatus() == CallModel::CallStatusIncoming) {
lastCall = call;
}
}
return lastCall;
}
QSharedPointer<CallModel> CallsListModel::getCallModel(const std::shared_ptr<linphone::Call> &call) const{
QSharedPointer<CallModel> CallsListModel::getCallModel(const std::shared_ptr<linphone::Call> &call) const {
QSharedPointer<CallModel> callModel;
if(call) {
auto itCall = std::find_if(mList.begin(), mList.end(), [call](const QSharedPointer<QObject> &item){
if (call) {
auto itCall = std::find_if(mList.begin(), mList.end(), [call](const QSharedPointer<QObject> &item) {
auto c = item.objectCast<CallModel>();
return c && c->getCall() == call;
});
if( itCall != mList.end())
callModel = itCall->objectCast<CallModel>();
if (itCall != mList.end()) callModel = itCall->objectCast<CallModel>();
}
return callModel;
}
void CallsListModel::acceptLastIncomingCall(bool video) {
auto call = getLastCall(true);
if(call) {
if(video) call->acceptWithVideo();
if (call) {
if (video) call->acceptWithVideo();
else call->accept();
}
}
void CallsListModel::terminateLastCall() {
auto call = getLastCall(false); // Allow to terminate last outgoing call
if(call) call->terminate();
auto call = getLastCall(false); // Allow to terminate last outgoing call
if (call) call->terminate();
}
void CallsListModel::toggleMuteSpeaker() {
auto currentCall = getCallModel(CoreManager::getInstance()->getCore()->getCurrentCall());
if(currentCall) currentCall->setSpeakerMuted(!currentCall->getSpeakerMuted());
if (currentCall) currentCall->setSpeakerMuted(!currentCall->getSpeakerMuted());
}
void CallsListModel::toggleMuteMicrophone() {
auto currentCall = getCallModel(CoreManager::getInstance()->getCore()->getCurrentCall());
if(currentCall) currentCall->setMicroMuted(!currentCall->getMicroMuted());
if (currentCall) currentCall->setMicroMuted(!currentCall->getMicroMuted());
}
std::list<std::shared_ptr<linphone::CallLog>> CallsListModel::getCallHistory(const QString& peerAddress, const QString& localAddress){
std::list<std::shared_ptr<linphone::CallLog>> CallsListModel::getCallHistory(const QString &peerAddress,
const QString &localAddress) {
std::shared_ptr<linphone::Address> cleanedPeerAddress = Utils::interpretUrl(Utils::cleanSipAddress(peerAddress));
std::shared_ptr<linphone::Address> cleanedLocalAddress = Utils::interpretUrl(Utils::cleanSipAddress(localAddress));
return CoreManager::getInstance()->getCore()->getCallHistory(cleanedPeerAddress, cleanedLocalAddress);
@ -558,19 +558,30 @@ std::list<std::shared_ptr<linphone::CallLog>> CallsListModel::getCallHistory(con
// -----------------------------------------------------------------------------
static void joinConference (const shared_ptr<linphone::Call> &call) {
if (call->getToHeader("method") != "join-conference")
return;
static void joinConference(const shared_ptr<linphone::Call> &call) {
if (call->getToHeader("method") != "join-conference") return;
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
if (!core->getConference()) {
if (!core->isInConference()) {
qWarning() << QStringLiteral("Not in a conference. => Responding to `join-conference` as a simple call...");
return;
}
shared_ptr<linphone::Conference> conference =
core->searchConferenceByIdentifier(call->getToHeader("conference-id"));
const QString conferenceId = Utils::coreStringToAppString(call->getToHeader("conference-id"));
if (!conference) {
qWarning()
<< QStringLiteral(
"Trying to join conference with an invalid conference id: `%1`. Responding as a simple call...")
.arg(conferenceId);
return;
}
qInfo() << QStringLiteral("Join conference: `%1`.").arg(conferenceId);
ConferenceHelperModel helperModel;
ConferenceHelperModel::ConferenceAddModel *addModel = helperModel.getConferenceAddModel();
if(call->dataExists("call-model")){
if (call->dataExists("call-model")) {
CallModel *callModel = &call->getData<CallModel>("call-model");
callModel->accept();
addModel->addToConference(call->getRemoteAddress());
@ -579,13 +590,13 @@ static void joinConference (const shared_ptr<linphone::Call> &call) {
}
// Global handler on core (is call before call model receive it). Used for model creation.
void CallsListModel::handleCallStateChanged (const shared_ptr<linphone::Call> &call, linphone::Call::State state) {
void CallsListModel::handleCallStateChanged(const shared_ptr<linphone::Call> &call, linphone::Call::State state) {
switch (state) {
case linphone::Call::State::IncomingReceived:
addCall(call);
joinConference(call);
break;
case linphone::Call::State::OutgoingInit:
addCall(call);
break;
@ -595,27 +606,26 @@ void CallsListModel::handleCallStateChanged (const shared_ptr<linphone::Call> &c
}
// Call handler
void CallsListModel::handleCallStatusChanged () {
auto callModel = qobject_cast<CallModel*>(sender());
void CallsListModel::handleCallStatusChanged() {
auto callModel = qobject_cast<CallModel *>(sender());
auto call = callModel->getCall();
if( call){
if (call) {
auto state = call->getState();
switch (state) {
case linphone::Call::State::End:
case linphone::Call::State::Error:{
case linphone::Call::State::Error: {
callModel->endCall();
if(callModel->getCallError() == "")
removeCall(call);
if (callModel->getCallError() == "") removeCall(call);
} break;
case linphone::Call::State::Released:
removeCall(call);
break;
break;
case linphone::Call::State::StreamsRunning: {
int index = findCallIndex(mList, call);
emit callRunning(index, callModel);
} break;
default:
break;
}
@ -624,42 +634,39 @@ void CallsListModel::handleCallStatusChanged () {
// -----------------------------------------------------------------------------
void CallsListModel::addCall (const shared_ptr<linphone::Call> &call) {
void CallsListModel::addCall(const shared_ptr<linphone::Call> &call) {
int index = findCallIndex(mList, call);
if( index < 0){
if (index < 0) {
QSharedPointer<CallModel> callModel = QSharedPointer<CallModel>(new CallModel(call), &QObject::deleteLater);
qInfo() << QStringLiteral("Add call:") << callModel->getFullLocalAddress() << callModel->getFullPeerAddress();
App::getInstance()->getEngine()->setObjectOwnership(callModel.get(), QQmlEngine::CppOwnership);
connect(callModel.get(), &CallModel::meAdminChanged, this, &CallsListModel::canMergeCallsChanged);
connect(callModel.get(), &CallModel::statusChanged, this, &CallsListModel::handleCallStatusChanged);
add(callModel);
if (call->getDir() == linphone::Call::Dir::Outgoing) {
QQuickWindow *callsWindow = App::getInstance()->getCallsWindow();
if (callsWindow) {
if (CoreManager::getInstance()->getSettingsModel()->getKeepCallsWindowInBackground()) {
if (!callsWindow->isVisible())
callsWindow->showMinimized();
} else
App::smartShowWindow(callsWindow);
if (!callsWindow->isVisible()) callsWindow->showMinimized();
} else App::smartShowWindow(callsWindow);
}
}
}
}
void CallsListModel::addDummyCall () {
void CallsListModel::addDummyCall() {
QQuickWindow *callsWindow = App::getInstance()->getCallsWindow();
if (callsWindow) {
App::smartShowWindow(callsWindow);
App::smartShowWindow(callsWindow);
}
QSharedPointer<CallModel> callModel = QSharedPointer<CallModel>(new CallModel(nullptr), &QObject::deleteLater);
qInfo() << QStringLiteral("Add call:") << callModel->getFullLocalAddress() << callModel->getFullPeerAddress();
App::getInstance()->getEngine()->setObjectOwnership(callModel.get(), QQmlEngine::CppOwnership);
// This connection is (only) useful for `CallsListProxyModel`.
QObject::connect(callModel.get(), &CallModel::isInConferenceChanged, this, [this, callModel](bool) {
int id = findCallIndex(mList, *callModel);
@ -667,26 +674,23 @@ void CallsListModel::addDummyCall () {
});
connect(callModel.get(), &CallModel::meAdminChanged, this, &CallsListModel::canMergeCallsChanged);
connect(callModel.get(), &CallModel::statusChanged, this, &CallsListModel::handleCallStatusChanged);
add(callModel);
}
void CallsListModel::removeCall (const shared_ptr<linphone::Call> &call) {
void CallsListModel::removeCall(const shared_ptr<linphone::Call> &call) {
CallModel *callModel = nullptr;
if(!call->dataExists("call-model"))
return;
if (!call->dataExists("call-model")) return;
callModel = &call->getData<CallModel>("call-model");
if( callModel && callModel->getCallError() != ""){ // Wait some time to display an error on ending call.
QTimer::singleShot( DelayBeforeRemoveCall , this, [this, callModel] {
removeCallCb(callModel);
});
}else{
if (callModel && callModel->getCallError() != "") { // Wait some time to display an error on ending call.
QTimer::singleShot(DelayBeforeRemoveCall, this, [this, callModel] { removeCallCb(callModel); });
} else {
remove(callModel);
}
}
void CallsListModel::removeCallCb (CallModel *callModel) {
void CallsListModel::removeCallCb(CallModel *callModel) {
callModel->removeCall();
remove(callModel);
}

View file

@ -146,12 +146,14 @@ bool ConferenceHelperModel::ConferenceAddModel::removeFromConference (const QStr
// -----------------------------------------------------------------------------
void ConferenceHelperModel::ConferenceAddModel::update () {
shared_ptr<linphone::Conference> conference = mConferenceHelperModel->mCore->getConference();
shared_ptr<linphone::Conference> conference;
auto currentCall = CoreManager::getInstance()->getCore()->getCurrentCall();
bool enablingVideo = false;
if( currentCall )
enablingVideo = currentCall->getCurrentParams()->videoEnabled();
if( currentCall ) {
enablingVideo = currentCall->getCurrentParams()->videoEnabled();
conference = currentCall->getConference();
}
if(!conference){
auto parameters = mConferenceHelperModel->mCore->createConferenceParams(conference);
if(!CoreManager::getInstance()->getSettingsModel()->getVideoConferenceEnabled()) {

View file

@ -69,15 +69,25 @@ void ConferenceProxyModel::terminate () {
void ConferenceProxyModel::startRecording () {
if (mRecording)
return;
CoreManager *coreManager = CoreManager::getInstance();
auto currentCall = coreManager->getCore()->getCurrentCall();
if (!currentCall) {
qWarning() << "Cannot start record: No call is running";
return;
}
auto conference = currentCall->getConference();
if (!conference) {
qWarning() << "Cannot start record: Current call is not a conference";
return;
}
qInfo() << QStringLiteral("Start recording conference:") << this;
CoreManager *coreManager = CoreManager::getInstance();
mLastRecordFile =
QStringLiteral("%1%2.mkv")
.arg(coreManager->getSettingsModel()->getSavedCallsFolder())
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss"));
coreManager->getCore()->startConferenceRecording(Utils::appStringToCoreString(mLastRecordFile) );
conference->startRecording(Utils::appStringToCoreString(mLastRecordFile) );
mRecording = true;
emit recordingChanged(true);
@ -86,12 +96,22 @@ void ConferenceProxyModel::startRecording () {
void ConferenceProxyModel::stopRecording () {
if (!mRecording)
return;
CoreManager *coreManager = CoreManager::getInstance();
auto currentCall = coreManager->getCore()->getCurrentCall();
if (!currentCall) {
qWarning() << "Cannot stop record: No call is running";
return;
}
auto conference = currentCall->getConference();
if (!conference) {
qWarning() << "Cannot stop record: Current call is not a conference";
return;
}
qInfo() << QStringLiteral("Stop recording conference:") << this;
mRecording = false;
CoreManager::getInstance()->getCore()->stopConferenceRecording();
conference->stopRecording();
App::getInstance()->getNotifier()->notifyRecordingCompleted(mLastRecordFile);
emit recordingChanged(false);

View file

@ -20,216 +20,203 @@
#include <QQmlApplicationEngine>
#include "app/App.hpp"
#include "components/core/CoreManager.hpp"
#include "ContactModel.hpp"
#include "VcardModel.hpp"
#include "app/App.hpp"
#include "components/core/CoreManager.hpp"
// =============================================================================
using namespace std;
ContactModel::ContactModel (shared_ptr<linphone::Friend> linphoneFriend, QObject * parent) : QObject(parent) {
Q_CHECK_PTR(linphoneFriend);
ContactModel::ContactModel(shared_ptr<linphone::Friend> linphoneFriend, QObject *parent) : QObject(parent) {
Q_CHECK_PTR(linphoneFriend);
mLinphoneFriend = linphoneFriend;
mLinphoneFriend->setData("contact-model", *this);
mLinphoneFriend = linphoneFriend;
mLinphoneFriend->setData("contact-model", *this);
setVcardModelInternal(new VcardModel(linphoneFriend->getVcard()));
setVcardModelInternal(new VcardModel(linphoneFriend->getVcard()));
}
ContactModel::ContactModel (VcardModel *vcardModel, QObject * parent) : QObject(parent) {
Q_CHECK_PTR(vcardModel);
Q_CHECK_PTR(vcardModel->mVcard);
Q_ASSERT(!vcardModel->mIsReadOnly);
mLinphoneFriend = CoreManager::getInstance()->getCore()->createFriendFromVcard(vcardModel->mVcard);
mLinphoneFriend->setData("contact-model", *this);
if(mLinphoneFriend)
qInfo() << QStringLiteral("Create contact from vcard:") << this << vcardModel;
else
qCritical() << QStringLiteral("Friend couldn't be created for vcard:") << this << vcardModel;
setVcardModelInternal(vcardModel);
ContactModel::ContactModel(VcardModel *vcardModel, QObject *parent) : QObject(parent) {
Q_CHECK_PTR(vcardModel);
Q_CHECK_PTR(vcardModel->mVcard);
Q_ASSERT(!vcardModel->mIsReadOnly);
mLinphoneFriend = CoreManager::getInstance()->getCore()->createFriendFromVcard(vcardModel->mVcard);
if (mLinphoneFriend) {
qInfo() << QStringLiteral("Create contact from vcard:") << this << vcardModel;
mLinphoneFriend->setData("contact-model", *this);
} else qCritical() << QStringLiteral("Friend couldn't be created for vcard:") << this << vcardModel;
setVcardModelInternal(vcardModel);
}
ContactModel::~ContactModel(){
ContactModel::~ContactModel() {
mVcardModel = nullptr;
mLinphoneFriend = nullptr;
}
// -----------------------------------------------------------------------------
void ContactModel::refreshPresence () {
Presence::PresenceStatus status = static_cast<Presence::PresenceStatus>(
mLinphoneFriend->getConsolidatedPresence()
);
void ContactModel::refreshPresence() {
Presence::PresenceStatus status = static_cast<Presence::PresenceStatus>(mLinphoneFriend->getConsolidatedPresence());
emit presenceStatusChanged(status);
emit presenceLevelChanged(Presence::getPresenceLevel(status));
emit presenceStatusChanged(status);
emit presenceLevelChanged(Presence::getPresenceLevel(status));
}
// -----------------------------------------------------------------------------
VcardModel *ContactModel::getVcardModel () const {
return mVcardModel;
VcardModel *ContactModel::getVcardModel() const {
return mVcardModel;
}
// -----------------------------------------------------------------------------
void ContactModel::setVcardModel (VcardModel *vcardModel) {
VcardModel *oldVcardModel = mVcardModel;
void ContactModel::setVcardModel(VcardModel *vcardModel) {
VcardModel *oldVcardModel = mVcardModel;
qInfo() << QStringLiteral("Remove vcard on contact:") << this << oldVcardModel;
oldVcardModel->mIsReadOnly = false;
oldVcardModel->mAvatarIsReadOnly = vcardModel->getAvatar() == oldVcardModel->getAvatar();
oldVcardModel->deleteLater();
qInfo() << QStringLiteral("Remove vcard on contact:") << this << oldVcardModel;
oldVcardModel->mIsReadOnly = false;
oldVcardModel->mAvatarIsReadOnly = vcardModel->getAvatar() == oldVcardModel->getAvatar();
oldVcardModel->deleteLater();
qInfo() << QStringLiteral("Set vcard on contact:") << this << vcardModel;
setVcardModelInternal(vcardModel);
qInfo() << QStringLiteral("Set vcard on contact:") << this << vcardModel;
setVcardModelInternal(vcardModel);
// Flush vcard.
mLinphoneFriend->done();
// Flush vcard.
mLinphoneFriend->done();
updateSipAddresses(oldVcardModel);
updateSipAddresses(oldVcardModel);
}
void ContactModel::setVcardModelInternal (VcardModel *vcardModel) {
Q_CHECK_PTR(vcardModel);
Q_ASSERT(vcardModel != mVcardModel);
void ContactModel::setVcardModelInternal(VcardModel *vcardModel) {
Q_CHECK_PTR(vcardModel);
Q_ASSERT(vcardModel != mVcardModel);
mVcardModel = vcardModel;
mVcardModel->mAvatarIsReadOnly = false;
mVcardModel->mIsReadOnly = true;
mVcardModel = vcardModel;
mVcardModel->mAvatarIsReadOnly = false;
mVcardModel->mIsReadOnly = true;
App::getInstance()->getEngine()->setObjectOwnership(mVcardModel, QQmlEngine::CppOwnership);
mVcardModel->setParent(this);
App::getInstance()->getEngine()->setObjectOwnership(mVcardModel, QQmlEngine::CppOwnership);
mVcardModel->setParent(this);
if (mLinphoneFriend->getVcard() != vcardModel->mVcard)
mLinphoneFriend->setVcard(vcardModel->mVcard);
if (mLinphoneFriend->getVcard() != vcardModel->mVcard) mLinphoneFriend->setVcard(vcardModel->mVcard);
}
void ContactModel::updateSipAddresses (VcardModel *oldVcardModel) {
Q_CHECK_PTR(oldVcardModel);
void ContactModel::updateSipAddresses(VcardModel *oldVcardModel) {
Q_CHECK_PTR(oldVcardModel);
QVariantList oldSipAddresses = oldVcardModel->getSipAddresses();
QVariantList sipAddresses = mVcardModel->getSipAddresses();
QSet<QString> done;
QVariantList oldSipAddresses = oldVcardModel->getSipAddresses();
QVariantList sipAddresses = mVcardModel->getSipAddresses();
QSet<QString> done;
for (const auto &variantA : oldSipAddresses) {
next:
const QString sipAddress = variantA.toString();
if (done.contains(sipAddress))
continue;
done.insert(sipAddress);
for (const auto &variantA : oldSipAddresses) {
next:
const QString sipAddress = variantA.toString();
if (done.contains(sipAddress)) continue;
done.insert(sipAddress);
// Check if old sip address exists in new set => No changes.
for (const auto &variantB : sipAddresses) {
if (sipAddress == variantB.toString())
goto next;
}
// Check if old sip address exists in new set => No changes.
for (const auto &variantB : sipAddresses) {
if (sipAddress == variantB.toString()) goto next;
}
emit sipAddressRemoved(sipAddress);
}
emit sipAddressRemoved(sipAddress);
}
oldSipAddresses.clear();
oldSipAddresses.clear();
for (const auto &variant : sipAddresses) {
const QString sipAddress = variant.toString();
if (done.contains(sipAddress))
continue;
done.insert(sipAddress);
for (const auto &variant : sipAddresses) {
const QString sipAddress = variant.toString();
if (done.contains(sipAddress)) continue;
done.insert(sipAddress);
emit sipAddressAdded(sipAddress);
}
emit sipAddressAdded(sipAddress);
}
emit contactUpdated();
emit contactUpdated();
}
// -----------------------------------------------------------------------------
void ContactModel::mergeVcardModel (VcardModel *vcardModel) {
Q_CHECK_PTR(vcardModel);
void ContactModel::mergeVcardModel(VcardModel *vcardModel) {
Q_CHECK_PTR(vcardModel);
qInfo() << QStringLiteral("Merge vcard into contact:") << this << vcardModel;
qInfo() << QStringLiteral("Merge vcard into contact:") << this << vcardModel;
// 1. Merge avatar.
if (vcardModel->getAvatar().isEmpty())
vcardModel->setAvatar(mVcardModel->getAvatar());
// 1. Merge avatar.
if (vcardModel->getAvatar().isEmpty()) vcardModel->setAvatar(mVcardModel->getAvatar());
// 2. Merge sip addresses, companies, emails and urls.
for (const auto &sipAddress : mVcardModel->getSipAddresses())
vcardModel->addSipAddress(sipAddress.toString());
for (const auto &company : mVcardModel->getCompanies())
vcardModel->addCompany(company.toString());
for (const auto &email : mVcardModel->getEmails())
vcardModel->addEmail(email.toString());
for (const auto &url : mVcardModel->getUrls())
vcardModel->addUrl(url.toString());
// 2. Merge sip addresses, companies, emails and urls.
for (const auto &sipAddress : mVcardModel->getSipAddresses())
vcardModel->addSipAddress(sipAddress.toString());
for (const auto &company : mVcardModel->getCompanies())
vcardModel->addCompany(company.toString());
for (const auto &email : mVcardModel->getEmails())
vcardModel->addEmail(email.toString());
for (const auto &url : mVcardModel->getUrls())
vcardModel->addUrl(url.toString());
// 3. Merge address.
{
const QVariantMap oldAddress = vcardModel->getAddress();
QVariantMap newAddress = vcardModel->getAddress();
// 3. Merge address.
{
const QVariantMap oldAddress = vcardModel->getAddress();
QVariantMap newAddress = vcardModel->getAddress();
constexpr const char *attributes[4] = { "street", "locality", "postalCode", "country" };
bool needMerge = true;
constexpr const char *attributes[4] = {"street", "locality", "postalCode", "country"};
bool needMerge = true;
for (const auto &attribute : attributes)
if (!newAddress[attribute].toString().isEmpty()) {
needMerge = false;
break;
}
for (const auto &attribute : attributes)
if (!newAddress[attribute].toString().isEmpty()) {
needMerge = false;
break;
}
if (needMerge) {
for (const auto &attribute : attributes)
newAddress[attribute] = oldAddress[attribute];
}
}
if (needMerge) {
for (const auto &attribute : attributes)
newAddress[attribute] = oldAddress[attribute];
}
}
setVcardModel(vcardModel);
setVcardModel(vcardModel);
}
// -----------------------------------------------------------------------------
VcardModel *ContactModel::cloneVcardModel () const {
shared_ptr<linphone::Vcard> vcard = mVcardModel->mVcard->clone();
Q_CHECK_PTR(vcard);
Q_CHECK_PTR(vcard->getVcard());
VcardModel *ContactModel::cloneVcardModel() const {
shared_ptr<linphone::Vcard> vcard = mVcardModel->mVcard->clone();
Q_CHECK_PTR(vcard);
Q_CHECK_PTR(vcard->getVcard());
mLinphoneFriend->edit();
mLinphoneFriend->edit();
VcardModel *vcardModel = new VcardModel(vcard);
vcardModel->mIsReadOnly = false;
VcardModel *vcardModel = new VcardModel(vcard);
vcardModel->mIsReadOnly = false;
qInfo() << QStringLiteral("Clone vcard from contact:") << this << vcardModel;
qInfo() << QStringLiteral("Clone vcard from contact:") << this << vcardModel;
return vcardModel;
return vcardModel;
}
// -----------------------------------------------------------------------------
Presence::PresenceStatus ContactModel::getPresenceStatus () const {
return static_cast<Presence::PresenceStatus>(mLinphoneFriend->getConsolidatedPresence());
Presence::PresenceStatus ContactModel::getPresenceStatus() const {
return static_cast<Presence::PresenceStatus>(mLinphoneFriend->getConsolidatedPresence());
}
QDateTime ContactModel::getPresenceTimestamp() const{
if(mLinphoneFriend->getPresenceModel()){
time_t timestamp = mLinphoneFriend->getPresenceModel()->getLatestActivityTimestamp();
if(timestamp == -1)
return QDateTime();
else
return QDateTime::fromMSecsSinceEpoch(timestamp * 1000);
}else
return QDateTime();
QDateTime ContactModel::getPresenceTimestamp() const {
if (mLinphoneFriend->getPresenceModel()) {
time_t timestamp = mLinphoneFriend->getPresenceModel()->getLatestActivityTimestamp();
if (timestamp == -1) return QDateTime();
else return QDateTime::fromMSecsSinceEpoch(timestamp * 1000);
} else return QDateTime();
}
Presence::PresenceLevel ContactModel::getPresenceLevel () const {
return Presence::getPresenceLevel(getPresenceStatus());
Presence::PresenceLevel ContactModel::getPresenceLevel() const {
return Presence::getPresenceLevel(getPresenceStatus());
}
bool ContactModel::hasCapability(const LinphoneEnums::FriendCapability& capability){
bool ContactModel::hasCapability(const LinphoneEnums::FriendCapability &capability) {
return mLinphoneFriend->hasCapability(LinphoneEnums::toLinphone(capability));
}
std::shared_ptr<linphone::Friend> ContactModel::getFriend() const{
std::shared_ptr<linphone::Friend> ContactModel::getFriend() const {
return mLinphoneFriend;
}

View file

@ -45,7 +45,7 @@ RecorderModel* RecorderManager::getVocalRecorder(){
if( !mVocalRecorder) {
auto core = CoreManager::getInstance()->getCore();
std::shared_ptr<linphone::RecorderParams> params = core->createRecorderParams();
params->setFileFormat(linphone::Recorder::FileFormat::Mkv);
params->setFileFormat(linphone::MediaFileFormat::Mkv);
params->setVideoCodec("");
auto recorder = core->createRecorder(params);
if(recorder)

@ -1 +1 @@
Subproject commit 280aea931a383a33851547bce5083ea22676f148
Subproject commit e1c2a336c2030d4523a3cc3d9127694a5272abe9