Browse Source

refactor(calls): make chatform sole owner of ToxCalls

* Keep ToxCall creation on call invite, since it tracks call state changes
* Fix ending call in ChatForm after CoreAv ends call from remote
* Pass ToxCall up on invite instead of answer, so that ownership is the same
before or after answer
* Do nothing if CoreAv tries to cancel call for non-existent call, to avoid
loop of CoreAv ending call, causing ChatForm to reset, causing ToxCall to
cancel call with CoreAv
pull/6235/head
Anthony Bilinski 5 years ago
parent
commit
4cb64e6fe2
No known key found for this signature in database
GPG Key ID: 2AA8E0DA1B31FB3C
  1. 14
      src/core/coreav.cpp
  2. 14
      src/core/coreav.h
  3. 16
      src/widget/form/chatform.cpp
  4. 2
      src/widget/form/chatform.h
  5. 2
      src/widget/form/groupchatform.h

14
src/core/coreav.cpp

@ -99,6 +99,7 @@ CoreAV::CoreAV(std::unique_ptr<ToxAV, ToxAVDeleter> toxav_, CompatibleRecursiveM @@ -99,6 +99,7 @@ CoreAV::CoreAV(std::unique_ptr<ToxAV, ToxAVDeleter> toxav_, CompatibleRecursiveM
connect(iterateTimer, &QTimer::timeout, this, &CoreAV::process);
connect(coreavThread.get(), &QThread::finished, iterateTimer, &QTimer::stop);
connect(coreavThread.get(), &QThread::started, this, &CoreAV::process);
qRegisterMetaType<ToxFriendCallPtr>("ToxFriendCallPtr");
}
void CoreAV::connectCallbacks()
@ -210,7 +211,7 @@ bool CoreAV::isCallActive(const Group* g) const @@ -210,7 +211,7 @@ bool CoreAV::isCallActive(const Group* g) const
return it->second->isActive();
}
CoreAV::ToxFriendCallPtr CoreAV::answerCall(uint32_t friendNum, bool video)
bool CoreAV::answerCall(uint32_t friendNum, bool video)
{
QWriteLocker locker{&callsLock};
QMutexLocker coreLocker{&coreLock};
@ -224,14 +225,14 @@ CoreAV::ToxFriendCallPtr CoreAV::answerCall(uint32_t friendNum, bool video) @@ -224,14 +225,14 @@ CoreAV::ToxFriendCallPtr CoreAV::answerCall(uint32_t friendNum, bool video)
if (toxav_answer(toxav.get(), friendNum, audioSettings.getAudioBitrate(),
videoBitrate, &err)) {
it->second->setActive(true);
return it->second;
return true;
} else {
qWarning() << "Failed to answer call with error" << err;
Toxav_Err_Call_Control controlErr;
toxav_call_control(toxav.get(), friendNum, TOXAV_CALL_CONTROL_CANCEL, &controlErr);
PARSE_ERR(controlErr);
calls.erase(it);
return {};
return false;
}
}
@ -262,7 +263,7 @@ CoreAV::ToxFriendCallPtr CoreAV::startCall(uint32_t friendNum, bool video) @@ -262,7 +263,7 @@ CoreAV::ToxFriendCallPtr CoreAV::startCall(uint32_t friendNum, bool video)
// Call object must be owned by this thread or there will be locking problems with Audio
call->moveToThread(thread());
assert(call != nullptr);
calls.emplace(friendNum, call);
calls.emplace(friendNum, call.get());
return call;
}
@ -273,7 +274,6 @@ bool CoreAV::cancelCall(uint32_t friendNum) @@ -273,7 +274,6 @@ bool CoreAV::cancelCall(uint32_t friendNum)
auto it = calls.find(friendNum);
if (it == calls.end()) {
qWarning() << QString("Can't cancel call with %1, it doesn't exist!").arg(friendNum);
return false;
}
@ -539,7 +539,7 @@ void CoreAV::callCallback(ToxAV* toxav, uint32_t friendNum, bool audio, bool vid @@ -539,7 +539,7 @@ void CoreAV::callCallback(ToxAV* toxav, uint32_t friendNum, bool audio, bool vid
call->moveToThread(self->thread());
assert(call != nullptr);
auto it = self->calls.emplace(friendNum, std::move(call));
auto it = self->calls.emplace(friendNum, call.get());
if (it.second == false) {
qWarning() << QString("Rejecting call invite from %1, we're already in that call!").arg(friendNum);
Toxav_Err_Call_Control err;
@ -560,7 +560,7 @@ void CoreAV::callCallback(ToxAV* toxav, uint32_t friendNum, bool audio, bool vid @@ -560,7 +560,7 @@ void CoreAV::callCallback(ToxAV* toxav, uint32_t friendNum, bool audio, bool vid
// Must explicitely unlock, because a deadlock can happen via ChatForm/Audio
locker.unlock();
emit self->avInvite(friendNum, video);
emit self->avInvite(friendNum, video, call);
}
void CoreAV::stateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t state, void* vSelf)

14
src/core/coreav.h

@ -24,6 +24,7 @@ @@ -24,6 +24,7 @@
#include "util/compatiblerecursivemutex.h"
#include <QObject>
#include <QMetaType>
#include <QMutex>
#include <QReadWriteLock>
#include <atomic>
@ -44,14 +45,17 @@ class VideoFrame; @@ -44,14 +45,17 @@ class VideoFrame;
class Core;
struct vpx_image;
Q_DECLARE_METATYPE(std::shared_ptr<ToxFriendCall>)
class CoreAV : public QObject
{
Q_OBJECT
public:
using CoreAVPtr = std::unique_ptr<CoreAV>;
// must be shared for signal avInvites signal, even though ownership is not shared
using ToxFriendCallPtr = std::shared_ptr<ToxFriendCall>;
using ToxGroupCallPtr = std::shared_ptr<ToxGroupCall>;
using ToxGroupCallPtr = std::unique_ptr<ToxGroupCall>;
static CoreAVPtr makeCoreAV(Tox* core, CompatibleRecursiveMutex& toxCoreLock,
IAudioSettings& audioSettings, IGroupSettings& groupSettings,
@ -80,12 +84,12 @@ public: @@ -80,12 +84,12 @@ public:
public slots:
ToxFriendCallPtr startCall(uint32_t friendNum, bool video);
ToxFriendCallPtr answerCall(uint32_t friendNum, bool video);
bool answerCall(uint32_t friendNum, bool video);
bool cancelCall(uint32_t friendNum);
void start();
signals:
void avInvite(uint32_t friendId, bool video);
void avInvite(uint32_t friendId, bool video, ToxFriendCallPtr call);
void avStart(uint32_t friendId, bool video);
void avEnd(uint32_t friendId, bool error = false);
@ -131,13 +135,13 @@ private: @@ -131,13 +135,13 @@ private:
* @brief Maps friend IDs to ToxFriendCall.
* @note Need to use STL container here, because Qt containers need a copy constructor.
*/
std::map<uint32_t, ToxFriendCallPtr> calls;
std::map<uint32_t, ToxFriendCall*> calls;
/**
* @brief Maps group IDs to ToxGroupCalls.
* @note Need to use STL container here, because Qt containers need a copy constructor.
*/
std::map<int, ToxGroupCallPtr> groupCalls;
std::map<int, ToxGroupCall*> groupCalls;
// protect 'calls' and 'groupCalls'
mutable QReadWriteLock callsLock{QReadWriteLock::Recursive};

16
src/widget/form/chatform.cpp

@ -314,12 +314,16 @@ void ChatForm::onAttachClicked() @@ -314,12 +314,16 @@ void ChatForm::onAttachClicked()
}
}
void ChatForm::onAvInvite(uint32_t friendId, bool video)
void ChatForm::onAvInvite(uint32_t friendId, bool video, std::shared_ptr<ToxFriendCall> callInvite)
{
if (friendId != f->getId()) {
return;
}
assert(!call);
call = callInvite;
QString displayedName = f->getDisplayedName();
SystemMessage systemMessage;
@ -364,6 +368,7 @@ void ChatForm::onAvEnd(uint32_t friendId, bool error) @@ -364,6 +368,7 @@ void ChatForm::onAvEnd(uint32_t friendId, bool error)
return;
}
call.reset();
headWidget->removeCallConfirm();
// Fixes an OS X bug with ending a call while in full screen
if (netcam && netcam->isFullScreen()) {
@ -394,14 +399,15 @@ void ChatForm::onAnswerCallTriggered(bool video) @@ -394,14 +399,15 @@ void ChatForm::onAnswerCallTriggered(bool video)
emit acceptCall(friendId);
updateCallButtons();
if (call) {
qDebug() << "Stale call detected";
if (!call) {
qWarning() << "Trying to answer call without receiving an invite";
}
CoreAV* av = core.getAv();
call = av->answerCall(friendId, video);
if (!call) {
bool answered = av->answerCall(friendId, video);
if (!answered) {
qDebug() << "Failed to answer call";
call.reset();
updateCallButtons();
stopCounter();
hideNetcam();

2
src/widget/form/chatform.h

@ -79,7 +79,7 @@ signals: @@ -79,7 +79,7 @@ signals:
void updateFriendActivity(Friend& frnd);
public slots:
void onAvInvite(uint32_t friendId, bool video);
void onAvInvite(uint32_t friendId, bool video, std::shared_ptr<ToxFriendCall> callInvite);
void onAvStart(uint32_t friendId, bool video);
void onAvEnd(uint32_t friendId, bool error);
void onAvatarChanged(const ToxPk& friendPk, const QPixmap& pic);

2
src/widget/form/groupchatform.h

@ -92,5 +92,5 @@ private: @@ -92,5 +92,5 @@ private:
Settings& settings;
Style& style;
FriendList& friendList;
std::shared_ptr<ToxGroupCall> call;
std::unique_ptr<ToxGroupCall> call;
};

Loading…
Cancel
Save