1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

Fix stack smashing, QTimer threading

QTimer CAN NOT be handled from a different thread, we needed to push them to the Core's thread

Allocating a large video frame buffer on the stack is a Bad Idea(tm), this commit fixes a bad buffer overflow

Also improve our QTimer handling during calls, no need to disconnect/reconnect on call start/end, once is enough, and no need to keep them on the stack
This commit is contained in:
Tux3 / Mlkj / !Lev.uXFMLA 2014-07-07 00:03:37 +02:00
parent d68e35e3cb
commit 6ba8be3503
5 changed files with 58 additions and 43 deletions

View File

@ -34,7 +34,7 @@ QList<ToxFile> Core::fileSendQueue;
QList<ToxFile> Core::fileRecvQueue; QList<ToxFile> Core::fileRecvQueue;
ToxCall Core::calls[TOXAV_MAX_CALLS]; ToxCall Core::calls[TOXAV_MAX_CALLS];
Core::Core(Camera* cam) : Core::Core(Camera* cam, QThread *coreThread) :
tox(nullptr), camera(cam) tox(nullptr), camera(cam)
{ {
toxTimer = new QTimer(this); toxTimer = new QTimer(this);
@ -50,6 +50,21 @@ Core::Core(Camera* cam) :
//connect(fileTimer, &QTimer::timeout, this, &Core::fileHeartbeat); //connect(fileTimer, &QTimer::timeout, this, &Core::fileHeartbeat);
connect(bootstrapTimer, &QTimer::timeout, this, &Core::onBootstrapTimer); connect(bootstrapTimer, &QTimer::timeout, this, &Core::onBootstrapTimer);
connect(&Settings::getInstance(), &Settings::dhtServerListChanged, this, &Core::bootstrapDht); connect(&Settings::getInstance(), &Settings::dhtServerListChanged, this, &Core::bootstrapDht);
for (int i=0; i<TOXAV_MAX_CALLS;i++)
{
calls[i].playAudioTimer = new QTimer(this);
calls[i].sendAudioTimer = new QTimer(this);
calls[i].playVideoTimer = new QTimer(this);
calls[i].sendVideoTimer = new QTimer(this);
calls[i].audioBuffer.moveToThread(coreThread);
calls[i].playAudioTimer->moveToThread(coreThread);
calls[i].sendAudioTimer->moveToThread(coreThread);
calls[i].playVideoTimer->moveToThread(coreThread);
calls[i].sendVideoTimer->moveToThread(coreThread);
connect(calls[i].playVideoTimer, &QTimer::timeout, [this,i](){playCallVideo(i);});
connect(calls[i].sendVideoTimer, &QTimer::timeout, [this,i](){sendCallVideo(i);});
}
} }
Core::~Core() Core::~Core()
@ -1164,33 +1179,29 @@ void Core::prepareCall(int friendId, int callId, ToxAv* toxav, bool videoEnabled
if (calls[callId].audioOutput != nullptr) if (calls[callId].audioOutput != nullptr)
{ {
calls[callId].playAudioTimer.setInterval(5); calls[callId].playAudioTimer->setInterval(5);
calls[callId].playAudioTimer.setSingleShot(true); calls[callId].playAudioTimer->setSingleShot(true);
connect(&calls[callId].playAudioTimer, &QTimer::timeout, [=](){playCallAudio(callId,toxav);}); connect(calls[callId].playAudioTimer, &QTimer::timeout, [=](){playCallAudio(callId,toxav);});
calls[callId].playAudioTimer.start(); calls[callId].playAudioTimer->start();
} }
if (calls[callId].audioInput != nullptr) if (calls[callId].audioInput != nullptr)
{ {
calls[callId].sendAudioTimer.setInterval(5); calls[callId].sendAudioTimer->setInterval(5);
calls[callId].sendAudioTimer.setSingleShot(true); calls[callId].sendAudioTimer->setSingleShot(true);
connect(&calls[callId].sendAudioTimer, &QTimer::timeout, [=](){sendCallAudio(callId,toxav);}); connect(calls[callId].sendAudioTimer, &QTimer::timeout, [=](){sendCallAudio(callId,toxav);});
calls[callId].sendAudioTimer.start(); calls[callId].sendAudioTimer->start();
} }
if (calls[callId].videoEnabled) if (calls[callId].videoEnabled)
{ {
calls[callId].playVideoTimer.setInterval(50); calls[callId].playVideoTimer->setInterval(50);
calls[callId].playVideoTimer.setSingleShot(true); calls[callId].playVideoTimer->setSingleShot(true);
connect(&calls[callId].playVideoTimer, &QTimer::timeout, [=](){ calls[callId].playVideoTimer->start();
Widget::getInstance()->getCore()->playCallVideo(callId);});
calls[callId].playVideoTimer.start();
calls[callId].sendVideoTimer.setInterval(50); calls[callId].sendVideoTimer->setInterval(50);
calls[callId].sendVideoTimer.setSingleShot(true); calls[callId].sendVideoTimer->setSingleShot(true);
connect(&calls[callId].sendVideoTimer, &QTimer::timeout, [=](){ calls[callId].sendVideoTimer->start();
Widget::getInstance()->getCore()->sendCallVideo(callId);});
calls[callId].sendVideoTimer.start();
Widget::getInstance()->getCamera()->suscribe(); Widget::getInstance()->getCamera()->suscribe();
} }
@ -1200,14 +1211,12 @@ void Core::cleanupCall(int callId)
{ {
qDebug() << QString("Core: cleaning up call %1").arg(callId); qDebug() << QString("Core: cleaning up call %1").arg(callId);
calls[callId].active = false; calls[callId].active = false;
disconnect(&calls[callId].playAudioTimer,0,0,0); disconnect(calls[callId].playAudioTimer,0,0,0);
disconnect(&calls[callId].sendAudioTimer,0,0,0); disconnect(calls[callId].sendAudioTimer,0,0,0);
disconnect(&calls[callId].playVideoTimer,0,0,0); calls[callId].playAudioTimer->stop();
disconnect(&calls[callId].sendVideoTimer,0,0,0); calls[callId].sendAudioTimer->stop();
calls[callId].playAudioTimer.stop(); calls[callId].playVideoTimer->stop();
calls[callId].sendAudioTimer.stop(); calls[callId].sendVideoTimer->stop();
calls[callId].playVideoTimer.stop();
calls[callId].sendVideoTimer.stop();
if (calls[callId].audioOutput != nullptr) if (calls[callId].audioOutput != nullptr)
{ {
delete calls[callId].audioOutput; delete calls[callId].audioOutput;
@ -1238,12 +1247,12 @@ void Core::playCallAudio(int callId, ToxAv* toxav)
return; return;
} }
qDebug() << QString("Core::playCallAudio: Error receiving audio: %1").arg(len); qDebug() << QString("Core::playCallAudio: Error receiving audio: %1").arg(len);
calls[callId].playAudioTimer.start(); calls[callId].playAudioTimer->start();
return; return;
} }
if (len == 0) if (len == 0)
{ {
calls[callId].playAudioTimer.start(); calls[callId].playAudioTimer->start();
return; return;
} }
//qDebug() << QString("Core: Received %1 bytes, %2 audio bytes free, %3 core buffer size") //qDebug() << QString("Core: Received %1 bytes, %2 audio bytes free, %3 core buffer size")
@ -1260,7 +1269,7 @@ void Core::playCallAudio(int callId, ToxAv* toxav)
if (error != QAudio::NoError) if (error != QAudio::NoError)
qWarning() << QString("Core::playCallAudio: Error: %1").arg(error); qWarning() << QString("Core::playCallAudio: Error: %1").arg(error);
calls[callId].playAudioTimer.start(); calls[callId].playAudioTimer->start();
} }
void Core::sendCallAudio(int callId, ToxAv* toxav) void Core::sendCallAudio(int callId, ToxAv* toxav)
@ -1277,20 +1286,20 @@ void Core::sendCallAudio(int callId, ToxAv* toxav)
if (result < 0) if (result < 0)
{ {
qWarning() << QString("Core: Unable to prepare audio frame, error %1").arg(result); qWarning() << QString("Core: Unable to prepare audio frame, error %1").arg(result);
calls[callId].sendAudioTimer.start(); calls[callId].sendAudioTimer->start();
return; return;
} }
result = toxav_send_audio(toxav, callId, dest, result); result = toxav_send_audio(toxav, callId, dest, result);
if (result < 0) if (result < 0)
{ {
qWarning() << QString("Core: Unable to send audio frame, error %1").arg(result); qWarning() << QString("Core: Unable to send audio frame, error %1").arg(result);
calls[callId].sendAudioTimer.start(); calls[callId].sendAudioTimer->start();
return; return;
} }
calls[callId].sendAudioTimer.start(); calls[callId].sendAudioTimer->start();
} }
else else
calls[callId].sendAudioTimer.start(); calls[callId].sendAudioTimer->start();
} }
void Core::playCallVideo(int callId) void Core::playCallVideo(int callId)
@ -1312,7 +1321,7 @@ void Core::playCallVideo(int callId)
else else
qDebug() << "Core: Error receiving video frame\n"; qDebug() << "Core: Error receiving video frame\n";
calls[callId].playVideoTimer.start(); calls[callId].playVideoTimer->start();
} }
void Core::sendCallVideo(int callId) void Core::sendCallVideo(int callId)
@ -1320,8 +1329,8 @@ void Core::sendCallVideo(int callId)
if (!calls[callId].active || !calls[callId].videoEnabled) if (!calls[callId].active || !calls[callId].videoEnabled)
return; return;
const int bufsize = TOXAV_MAX_VIDEO_WIDTH * TOXAV_MAX_VIDEO_HEIGHT * 4; static const int bufsize = TOXAV_MAX_VIDEO_WIDTH * TOXAV_MAX_VIDEO_HEIGHT * 4;
uint8_t videobuf[bufsize]; static uint8_t* videobuf = new uint8_t[bufsize];
vpx_image frame = camera->getLastVPXImage(); vpx_image frame = camera->getLastVPXImage();
if (frame.w && frame.h) if (frame.w && frame.h)
{ {
@ -1329,7 +1338,7 @@ void Core::sendCallVideo(int callId)
if((result = toxav_prepare_video_frame(toxav, callId, videobuf, bufsize, &frame)) < 0) if((result = toxav_prepare_video_frame(toxav, callId, videobuf, bufsize, &frame)) < 0)
{ {
qDebug() << QString("Core: toxav_prepare_video_frame: error %1").arg(result); qDebug() << QString("Core: toxav_prepare_video_frame: error %1").arg(result);
calls[callId].sendVideoTimer.start(); calls[callId].sendVideoTimer->start();
return; return;
} }
@ -1340,7 +1349,7 @@ void Core::sendCallVideo(int callId)
else else
qDebug("Core::sendCallVideo: Invalid frame (bad camera ?)"); qDebug("Core::sendCallVideo: Invalid frame (bad camera ?)");
calls[callId].sendVideoTimer.start(); calls[callId].sendVideoTimer->start();
} }
void Core::groupInviteFriend(int friendId, int groupId) void Core::groupInviteFriend(int friendId, int groupId)

4
core.h
View File

@ -98,7 +98,7 @@ public:
QAudioInput* audioInput; QAudioInput* audioInput;
QIODevice* audioInputDevice; QIODevice* audioInputDevice;
ToxAvCodecSettings codecSettings; ToxAvCodecSettings codecSettings;
QTimer playAudioTimer, sendAudioTimer, playVideoTimer, sendVideoTimer; QTimer *playAudioTimer, *sendAudioTimer, *playVideoTimer, *sendVideoTimer;
int callId; int callId;
int friendId; int friendId;
bool videoEnabled; bool videoEnabled;
@ -109,7 +109,7 @@ class Core : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit Core(Camera* cam); explicit Core(Camera* cam, QThread* coreThread);
~Core(); ~Core();
int getGroupNumberPeers(int groupId) const; int getGroupNumberPeers(int groupId) const;

View File

@ -35,7 +35,7 @@ GroupWidget::GroupWidget(int GroupId, QString Name)
textLayout.setMargin(0); textLayout.setMargin(0);
avatar.setPixmap(QPixmap(":img/group.png")); avatar.setPixmap(QPixmap(":img/group.png"));
statusPic.setPixmap(QPixmap(":img/status/dot_groupchat.png")); statusPic.setPixmap(QPixmap(":img/status/dot_online.png"));
name.setText(Name); name.setText(Name);
QFont small; QFont small;
small.setPixelSize(10); small.setPixelSize(10);

View File

@ -203,8 +203,8 @@ Widget::Widget(QWidget *parent) :
qRegisterMetaType<ToxFile>("ToxFile"); qRegisterMetaType<ToxFile>("ToxFile");
qRegisterMetaType<ToxFile::FileDirection>("ToxFile::FileDirection"); qRegisterMetaType<ToxFile::FileDirection>("ToxFile::FileDirection");
core = new Core(camera);
coreThread = new QThread(this); coreThread = new QThread(this);
core = new Core(camera, coreThread);
core->moveToThread(coreThread); core->moveToThread(coreThread);
connect(coreThread, &QThread::started, core, &Core::start); connect(coreThread, &QThread::started, core, &Core::start);
@ -293,6 +293,11 @@ void Widget::splitterMoved(int, int)
updateFriendListWidth(); updateFriendListWidth();
} }
QThread* Widget::getCoreThread()
{
return coreThread;
}
void Widget::updateFriendListWidth() void Widget::updateFriendListWidth()
{ {
int newWidth = ui->friendList->width(); int newWidth = ui->friendList->width();

View File

@ -52,6 +52,7 @@ public:
void setCentralWidget(QWidget *widget, const QString &widgetName); void setCentralWidget(QWidget *widget, const QString &widgetName);
QString getUsername(); QString getUsername();
Core* getCore(); Core* getCore();
QThread* getCoreThread();
Camera* getCamera(); Camera* getCamera();
static Widget* getInstance(); static Widget* getInstance();
void showTestCamview(); void showTestCamview();