Fix : Undefined bevaviour on core restart

- Remove useless mutex protection
- Remove the constraint on sender events from CoreHandlers. The fact that these events should be on a specific thread is done by the connection.
- Fully use the Global State Changed from SDK events and centralized app behaviour to them
- Reerite CoreManager initialization to avoid multiple lambda functions and to gain control over threads
- Add Start/Stop timer functions for iteration
This commit is contained in:
Julien Wadel 2020-11-05 10:17:26 +01:00
parent 0685257775
commit c6c8ed9918
6 changed files with 76 additions and 89 deletions

View file

@ -397,7 +397,7 @@ void App::initContentApp () {
QObject::connect(
CoreManager::getInstance(),
&CoreManager::coreStarted, CoreManager::getInstance(),
&CoreManager::managerInitialized, CoreManager::getInstance(),
[this, mustBeIconified]() mutable {
if(CoreManager::getInstance()->started())
openAppAfterInit(mustBeIconified);
@ -894,7 +894,7 @@ void App::openAppAfterInit (bool mustBeIconified) {
coreManager->getCallsListModel()->launchAudioCall(sipAddress);
}else{
QObject * context = new QObject();
QObject::connect(CoreManager::getInstance(), &CoreManager::coreStarted,context,
QObject::connect(CoreManager::getInstance(), &CoreManager::managerInitialized,context,
[sipAddress,coreManager, context]() mutable {
if(context){
delete context;

View file

@ -50,36 +50,13 @@ void scheduleFunctionInApp (function<void()> func) {
// -----------------------------------------------------------------------------
CoreHandlers::CoreHandlers (CoreManager *coreManager) {
mCoreStartedLock = new QMutex();
QObject::connect(coreManager, &CoreManager::coreCreated, this, &CoreHandlers::handleCoreCreated);
Q_UNUSED(coreManager)
}
CoreHandlers::~CoreHandlers () {
delete mCoreStartedLock;
mCoreStartedLock = nullptr;
}
// -----------------------------------------------------------------------------
void CoreHandlers::handleCoreCreated () {
mCoreStartedLock->lock();
Q_ASSERT(mCoreCreated == false);
mCoreCreated = true;
notifyCoreStarted();
mCoreStartedLock->unlock();
}
void CoreHandlers::notifyCoreStarted () {
if (mCoreCreated && mCoreStarted)
scheduleFunctionInApp([this] {
qInfo() << QStringLiteral("Core started.");
emit coreStarted();
});
}
// -----------------------------------------------------------------------------
void CoreHandlers::onAuthenticationRequested (
const shared_ptr<linphone::Core> & core,
const shared_ptr<linphone::AuthInfo> &authInfo,
@ -136,22 +113,23 @@ void CoreHandlers::onDtmfReceived(
const std::shared_ptr<linphone::Core> & lc,
const std::shared_ptr<linphone::Call> & call,
int dtmf) {
Q_UNUSED(lc)
Q_UNUSED(call)
CoreManager::getInstance()->getCore()->playDtmf((char)dtmf, CallModel::DtmfSoundDelay);
}
void CoreHandlers::onGlobalStateChanged (
const shared_ptr<linphone::Core> &,
const shared_ptr<linphone::Core> &core,
linphone::GlobalState gstate,
const string &
const string & message
) {
if (gstate == linphone::GlobalState::On) {
mCoreStartedLock->lock();
Q_ASSERT(mCoreStarted == false);
mCoreStarted = true;
notifyCoreStarted();
mCoreStartedLock->unlock();
}
Q_UNUSED(core)
Q_UNUSED(message)
if( gstate == linphone::GlobalState::On)
emit coreStarted();
else if( gstate == linphone::GlobalState::Off)
emit coreStopped();
else if( gstate == linphone::GlobalState::Startup)
emit coreStarting();
}
void CoreHandlers::onIsComposingReceived (
@ -256,6 +234,7 @@ void CoreHandlers::onTransferStateChanged (
case linphone::Call::State::Paused:
case linphone::Call::State::PausedByRemote:
case linphone::Call::State::Pausing:
case linphone::Call::State::PushIncomingReceived:
case linphone::Call::State::Referred:
case linphone::Call::State::Released:
case linphone::Call::State::Resuming:

View file

@ -45,7 +45,9 @@ signals:
void callTransferFailed (const std::shared_ptr<linphone::Call> &call);
void callTransferSucceeded (const std::shared_ptr<linphone::Call> &call);
void callCreated(const std::shared_ptr<linphone::Call> & call);
void coreStarting();
void coreStarted ();
void coreStopped ();
void isComposingChanged (const std::shared_ptr<linphone::ChatRoom> &chatRoom);
void logsUploadStateChanged (linphone::Core::LogCollectionUploadState state, const std::string &info);
void messageReceived (const std::shared_ptr<linphone::ChatMessage> &message);
@ -54,8 +56,6 @@ signals:
void ecCalibrationResult(linphone::EcCalibratorStatus status, int delayMs);
private:
void handleCoreCreated ();
void notifyCoreStarted ();
// ---------------------------------------------------------------------------
// Linphone callbacks.
@ -165,11 +165,6 @@ private:
) override;
// ---------------------------------------------------------------------------
bool mCoreCreated = false;
bool mCoreStarted = false;
QMutex *mCoreStartedLock = nullptr;
};
#endif // CORE_HANDLERS_H_

View file

@ -72,43 +72,39 @@ CoreManager *CoreManager::mInstance;
CoreManager::CoreManager (QObject *parent, const QString &configPath) :
QObject(parent), mHandlers(make_shared<CoreHandlers>(this)) {
QTimer * delayedCreationTimer = new QTimer();
delayedCreationTimer->setSingleShot(true);
QObject::connect(delayedCreationTimer, &QTimer::timeout, this , [configPath, this, delayedCreationTimer]{
delayedCreationTimer->deleteLater();
createLinphoneCore(configPath);
qInfo() << QStringLiteral("Core created. Enable iterate.");
mInstance->mCbsTimer->start();
std::shared_ptr<CoreHandlers> h = mInstance->getHandlers();// Protect handler as we will enter its function where it can be deleted (like while restarting)
emit mInstance->coreCreated();
});
mCore = nullptr;
CoreHandlers *coreHandlers = mHandlers.get();
QObject::connect(coreHandlers, &CoreHandlers::coreStarted, this, [] {
// Do not change this order. :) (Or pray.)
mInstance->mCallsListModel = new CallsListModel(mInstance);
mInstance->mContactsListModel = new ContactsListModel(mInstance);
mInstance->mAccountSettingsModel = new AccountSettingsModel(mInstance);
mInstance->mSettingsModel = new SettingsModel(mInstance);
mInstance->mSipAddressesModel = new SipAddressesModel(mInstance);
EventCountNotifier *eventCountNotifier = new EventCountNotifier(mInstance);
eventCountNotifier->updateUnreadMessageCount();
QObject::connect(eventCountNotifier, &EventCountNotifier::eventCountChanged,
mInstance, &CoreManager::eventCountChanged
);
mInstance->mEventCountNotifier = eventCountNotifier;
mInstance->migrate();
mInstance->mStarted = true;
emit mInstance->coreStarted();
});
QObject::connect(coreHandlers, &CoreHandlers::coreStarting, this, &CoreManager::startIterate, Qt::QueuedConnection);
QObject::connect(coreHandlers, &CoreHandlers::coreStarted, this, &CoreManager::initManager, Qt::QueuedConnection);
QObject::connect(coreHandlers, &CoreHandlers::coreStopped, this, &CoreManager::stopIterate, Qt::QueuedConnection);
QObject::connect(coreHandlers, &CoreHandlers::logsUploadStateChanged, this, &CoreManager::handleLogsUploadStateChanged);
delayedCreationTimer->start(CbsCallInterval);
createLinphoneCore(configPath);
}
CoreManager::~CoreManager(){
mCore->removeListener(mHandlers);
mHandlers = nullptr;// Call destructor
mCore = nullptr;// Call destructor
}
// -----------------------------------------------------------------------------
void CoreManager::initManager(){
mCallsListModel = new CallsListModel(this);
mContactsListModel = new ContactsListModel(this);
mAccountSettingsModel = new AccountSettingsModel(this);
mSettingsModel = new SettingsModel(this);
mSipAddressesModel = new SipAddressesModel(this);
mEventCountNotifier = new EventCountNotifier(this);
mEventCountNotifier->updateUnreadMessageCount();
QObject::connect(mEventCountNotifier, &EventCountNotifier::eventCountChanged,this, &CoreManager::eventCountChanged);
migrate();
mStarted = true;
qInfo() << QStringLiteral("Core created. Enable iterate.");
emit managerInitialized();
}
shared_ptr<ChatModel> CoreManager::getChatModel (const QString &peerAddress, const QString &localAddress) {
if (peerAddress.isEmpty() || localAddress.isEmpty())
return nullptr;
@ -161,13 +157,7 @@ HistoryModel* CoreManager::getHistoryModel(){
void CoreManager::init (QObject *parent, const QString &configPath) {
if (mInstance)
return;
mInstance = new CoreManager(parent, configPath);
QTimer *timer = mInstance->mCbsTimer = new QTimer(mInstance);
timer->setInterval(CbsCallInterval);
QObject::connect(timer, &QTimer::timeout, mInstance, &CoreManager::iterate);
}
void CoreManager::uninit () {
@ -176,8 +166,11 @@ void CoreManager::uninit () {
mInstance = nullptr;
qInfo() << "Linphone Core is destroyed";
});
mInstance->mCbsTimer->stop();
mInstance->deleteLater();// Ensure to take time to delete the instance
QObject::connect(mInstance->getHandlers().get(), &CoreHandlers::coreStopped, mInstance, &QObject::deleteLater);
mInstance->lockVideoRender();// Stop do iterations. We have to protect GUI.
mInstance->mCore->stop();
mInstance->unlockVideoRender();
QTest::qWaitFor([&]() {return mInstance == nullptr;},10000);
if( mInstance){
qWarning() << "Linphone Core couldn't destroy in time. It may lead to have multiple session of Linphone Core";
@ -338,12 +331,27 @@ int CoreManager::getMissedCallCount(const QString &peerAddress, const QString &l
int CoreManager::getMissedCallCountFromLocal( const QString &localAddress)const{
return mEventCountNotifier ? mEventCountNotifier->getMissedCallCountFromLocal(localAddress) : 0;
}
// -----------------------------------------------------------------------------
void CoreManager::startIterate(){
mCbsTimer = new QTimer(this);
mCbsTimer->setInterval(CbsCallInterval);
QObject::connect(mCbsTimer, &QTimer::timeout, this, &CoreManager::iterate);
mCbsTimer->start();
}
void CoreManager::stopIterate(){
mCbsTimer->stop();
mCbsTimer->deleteLater();// allow the timer to continue its stuff
mCbsTimer = nullptr;
}
void CoreManager::iterate () {
mInstance->lockVideoRender();
mCore->iterate();
mInstance->unlockVideoRender();
lockVideoRender();
if(mCore)
mCore->iterate();
unlockVideoRender();
}
// -----------------------------------------------------------------------------

View file

@ -137,9 +137,13 @@ public:
static bool isInstanciated(){return mInstance!=nullptr;}
public slots:
void initManager();
void startIterate();
void stopIterate();
signals:
void coreCreated ();
void coreStarted ();
void managerInitialized ();
void chatModelCreated (const std::shared_ptr<ChatModel> &chatModel);
void historyModelCreated (HistoryModel *historyModel);
@ -150,6 +154,7 @@ signals:
private:
CoreManager (QObject *parent, const QString &configPath);
~CoreManager ();
void setDatabasesPaths ();
void setOtherPaths ();

View file

@ -51,7 +51,7 @@ ApplicationWindow {
Connections {
target: CoreManager
onCoreStarted: mainLoader.active = true
onManagerInitialized: mainLoader.active = true
}
Shortcut {