mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Italian translation: update
This commit is contained in:
commit
303f1734e5
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
This program is libre 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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "audiobuffer.h"
|
||||
|
||||
AudioBuffer::AudioBuffer() :
|
||||
QIODevice(0)
|
||||
{
|
||||
open(QIODevice::ReadWrite);
|
||||
}
|
||||
|
||||
AudioBuffer::~AudioBuffer()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
qint64 AudioBuffer::readData(char *data, qint64 len)
|
||||
{
|
||||
qint64 total;
|
||||
bufferMutex.lock();
|
||||
try {
|
||||
total = qMin((qint64)buffer.size(), len);
|
||||
memcpy(data, buffer.constData(), total);
|
||||
buffer = buffer.mid(total);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
bufferMutex.unlock();
|
||||
return 0;
|
||||
}
|
||||
bufferMutex.unlock();
|
||||
return total;
|
||||
}
|
||||
|
||||
qint64 AudioBuffer::writeData(const char* data, qint64 len)
|
||||
{
|
||||
bufferMutex.lock();
|
||||
try {
|
||||
buffer.append(data, len);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
bufferMutex.unlock();
|
||||
return 0;
|
||||
}
|
||||
bufferMutex.unlock();
|
||||
return len;
|
||||
}
|
||||
|
||||
qint64 AudioBuffer::bytesAvailable() const
|
||||
{
|
||||
bufferMutex.lock();
|
||||
long long size = buffer.size() + QIODevice::bytesAvailable();
|
||||
bufferMutex.unlock();
|
||||
return size;
|
||||
}
|
||||
|
||||
qint64 AudioBuffer::bufferSize() const
|
||||
{
|
||||
bufferMutex.lock();
|
||||
long long size = buffer.size();
|
||||
bufferMutex.unlock();
|
||||
return size;
|
||||
}
|
||||
|
||||
void AudioBuffer::clear()
|
||||
{
|
||||
bufferMutex.lock();
|
||||
buffer.clear();
|
||||
bufferMutex.unlock();
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2014 by Project Tox <https://tox.im>
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
This program is libre 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 COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef AUDIOBUFFER_H
|
||||
#define AUDIOBUFFER_H
|
||||
|
||||
#include <QIODevice>
|
||||
#include <QByteArray>
|
||||
#include <QMutex>
|
||||
|
||||
class AudioBuffer : public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AudioBuffer();
|
||||
~AudioBuffer();
|
||||
|
||||
qint64 readData(char *data, qint64 maxlen);
|
||||
qint64 writeData(const char *data, qint64 len);
|
||||
qint64 bytesAvailable() const;
|
||||
qint64 bufferSize() const;
|
||||
void clear();
|
||||
|
||||
private:
|
||||
QByteArray buffer;
|
||||
mutable QMutex bufferMutex;
|
||||
};
|
||||
|
||||
#endif // AUDIOBUFFER_H
|
618
core.cpp
618
core.cpp
|
@ -21,6 +21,7 @@
|
|||
#include "widget/widget.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
|
@ -34,10 +35,6 @@
|
|||
const QString Core::CONFIG_FILE_NAME = "data";
|
||||
QList<ToxFile> Core::fileSendQueue;
|
||||
QList<ToxFile> Core::fileRecvQueue;
|
||||
ToxCall Core::calls[TOXAV_MAX_CALLS];
|
||||
const int Core::videobufsize{TOXAV_MAX_VIDEO_WIDTH * TOXAV_MAX_VIDEO_HEIGHT * 4};
|
||||
uint8_t* Core::videobuf;
|
||||
int Core::videoBusyness;
|
||||
|
||||
Core::Core(Camera* cam, QThread *coreThread) :
|
||||
tox(nullptr), camera(cam)
|
||||
|
@ -49,8 +46,6 @@ Core::Core(Camera* cam, QThread *coreThread) :
|
|||
toxTimer->setSingleShot(true);
|
||||
//saveTimer = new QTimer(this);
|
||||
//saveTimer->start(TOX_SAVE_INTERVAL);
|
||||
//fileTimer = new QTimer(this);
|
||||
//fileTimer->start(TOX_FILE_INTERVAL);
|
||||
bootstrapTimer = new QTimer(this);
|
||||
bootstrapTimer->start(TOX_BOOTSTRAP_INTERVAL);
|
||||
connect(toxTimer, &QTimer::timeout, this, &Core::process);
|
||||
|
@ -64,7 +59,6 @@ Core::Core(Camera* cam, QThread *coreThread) :
|
|||
{
|
||||
calls[i].sendAudioTimer = new QTimer();
|
||||
calls[i].sendVideoTimer = new QTimer();
|
||||
calls[i].audioBuffer.moveToThread(coreThread);
|
||||
calls[i].sendAudioTimer->moveToThread(coreThread);
|
||||
calls[i].sendVideoTimer->moveToThread(coreThread);
|
||||
connect(calls[i].sendVideoTimer, &QTimer::timeout, [this,i](){sendCallVideo(i);});
|
||||
|
@ -309,7 +303,10 @@ void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive
|
|||
file->status = ToxFile::TRANSMITTING;
|
||||
emit static_cast<Core*>(core)->fileTransferAccepted(*file);
|
||||
qDebug() << "Core: File control callback, file accepted";
|
||||
file->sendFuture = QtConcurrent::run(sendAllFileData, static_cast<Core*>(core), file);
|
||||
file->sendTimer = new QTimer(static_cast<Core*>(core));
|
||||
connect(file->sendTimer, &QTimer::timeout, std::bind(sendAllFileData,static_cast<Core*>(core), file));
|
||||
file->sendTimer->setSingleShot(true);
|
||||
file->sendTimer->start(TOX_FILE_INTERVAL);
|
||||
}
|
||||
else if (receive_send == 1 && control_type == TOX_FILECONTROL_KILL)
|
||||
{
|
||||
|
@ -317,7 +314,7 @@ void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive
|
|||
.arg(file->fileNum).arg(file->friendId);
|
||||
file->status = ToxFile::STOPPED;
|
||||
emit static_cast<Core*>(core)->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING);
|
||||
file->sendFuture.waitForFinished(); // Wait for sendAllFileData to return before deleting the ToxFile
|
||||
while (file->sendTimer) QThread::msleep(1); // Wait for sendAllFileData to return before deleting the ToxFile
|
||||
removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum);
|
||||
}
|
||||
else if (receive_send == 1 && control_type == TOX_FILECONTROL_FINISHED)
|
||||
|
@ -342,9 +339,9 @@ void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive
|
|||
.arg(file->fileNum).arg(file->friendId);
|
||||
file->status = ToxFile::STOPPED;
|
||||
emit static_cast<Core*>(core)->fileTransferFinished(*file);
|
||||
removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum);
|
||||
// confirm receive is complete
|
||||
tox_file_send_control(tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_FINISHED, nullptr, 0);
|
||||
removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -537,7 +534,7 @@ void Core::cancelFileSend(int friendId, int fileNum)
|
|||
file->status = ToxFile::STOPPED;
|
||||
emit fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING);
|
||||
tox_file_send_control(tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0);
|
||||
file->sendFuture.waitForFinished(); // Wait until sendAllFileData returns before deleting
|
||||
while (file->sendTimer) QThread::msleep(1); // Wait until sendAllFileData returns before deleting
|
||||
removeFileFromQueue(true, friendId, fileNum);
|
||||
}
|
||||
|
||||
|
@ -966,540 +963,77 @@ void Core::removeFileFromQueue(bool sendQueue, int friendId, int fileId)
|
|||
|
||||
void Core::sendAllFileData(Core *core, ToxFile* file)
|
||||
{
|
||||
while (file->bytesSent < file->filesize)
|
||||
if (file->status == ToxFile::PAUSED)
|
||||
{
|
||||
if (file->status == ToxFile::PAUSED)
|
||||
{
|
||||
QThread::sleep(5);
|
||||
continue;
|
||||
}
|
||||
else if (file->status == ToxFile::STOPPED)
|
||||
{
|
||||
qWarning("Core::sendAllFileData: File is stopped");
|
||||
return;
|
||||
}
|
||||
emit core->fileTransferInfo(file->friendId, file->fileNum, file->filesize, file->bytesSent, ToxFile::SENDING);
|
||||
qApp->processEvents();
|
||||
long long chunkSize = tox_file_data_size(core->tox, file->friendId);
|
||||
if (chunkSize == -1)
|
||||
{
|
||||
qWarning("Core::fileHeartbeat: Error getting preffered chunk size, aborting file send");
|
||||
file->status = ToxFile::STOPPED;
|
||||
emit core->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING);
|
||||
tox_file_send_control(core->tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0);
|
||||
removeFileFromQueue(true, file->friendId, file->fileNum);
|
||||
return;
|
||||
}
|
||||
qDebug() << "chunkSize: " << chunkSize;
|
||||
chunkSize = std::min(chunkSize, file->filesize);
|
||||
uint8_t* data = new uint8_t[chunkSize];
|
||||
file->file->seek(file->bytesSent);
|
||||
int readSize = file->file->read((char*)data, chunkSize);
|
||||
if (readSize == -1)
|
||||
{
|
||||
qWarning() << QString("Core::sendAllFileData: Error reading from file: %1").arg(file->file->errorString());
|
||||
delete[] data;
|
||||
QThread::msleep(5);
|
||||
continue;
|
||||
}
|
||||
else if (readSize == 0)
|
||||
{
|
||||
qWarning() << QString("Core::sendAllFileData: Nothing to read from file: %1").arg(file->file->errorString());
|
||||
delete[] data;
|
||||
QThread::msleep(5);
|
||||
continue;
|
||||
}
|
||||
if (tox_file_send_data(core->tox, file->friendId, file->fileNum, data, readSize) == -1)
|
||||
{
|
||||
//qWarning("Core::fileHeartbeat: Error sending data chunk");
|
||||
core->process();
|
||||
delete[] data;
|
||||
QThread::msleep(5);
|
||||
continue;
|
||||
}
|
||||
file->sendTimer->start(TOX_FILE_INTERVAL);
|
||||
return;
|
||||
}
|
||||
else if (file->status == ToxFile::STOPPED)
|
||||
{
|
||||
qWarning("Core::sendAllFileData: File is stopped");
|
||||
file->sendTimer->disconnect();
|
||||
delete file->sendTimer;
|
||||
file->sendTimer = nullptr;
|
||||
return;
|
||||
}
|
||||
emit core->fileTransferInfo(file->friendId, file->fileNum, file->filesize, file->bytesSent, ToxFile::SENDING);
|
||||
qApp->processEvents();
|
||||
long long chunkSize = tox_file_data_size(core->tox, file->friendId);
|
||||
if (chunkSize == -1)
|
||||
{
|
||||
qWarning("Core::fileHeartbeat: Error getting preffered chunk size, aborting file send");
|
||||
file->status = ToxFile::STOPPED;
|
||||
emit core->fileTransferCancelled(file->friendId, file->fileNum, ToxFile::SENDING);
|
||||
tox_file_send_control(core->tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_KILL, nullptr, 0);
|
||||
removeFileFromQueue(true, file->friendId, file->fileNum);
|
||||
return;
|
||||
}
|
||||
//qDebug() << "chunkSize: " << chunkSize;
|
||||
chunkSize = std::min(chunkSize, file->filesize);
|
||||
uint8_t* data = new uint8_t[chunkSize];
|
||||
file->file->seek(file->bytesSent);
|
||||
int readSize = file->file->read((char*)data, chunkSize);
|
||||
if (readSize == -1)
|
||||
{
|
||||
qWarning() << QString("Core::sendAllFileData: Error reading from file: %1").arg(file->file->errorString());
|
||||
delete[] data;
|
||||
file->bytesSent += readSize;
|
||||
//qDebug() << QString("Core::fileHeartbeat: sent %1/%2 bytes").arg(file->bytesSent).arg(file->fileData.size());
|
||||
}
|
||||
qDebug("Core::fileHeartbeat: Transfer finished");
|
||||
tox_file_send_control(core->tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_FINISHED, nullptr, 0);
|
||||
}
|
||||
|
||||
void Core::onAvInvite(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV invite";
|
||||
file->sendTimer->start(TOX_FILE_INTERVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
ToxAvCSettings* transSettings = new ToxAvCSettings;
|
||||
int err = toxav_get_peer_csettings(toxav, call_index, 0, transSettings);
|
||||
if (err != ErrorNone)
|
||||
else if (readSize == 0)
|
||||
{
|
||||
qWarning() << "Core::onAvInvite: error getting call type";
|
||||
delete transSettings;
|
||||
qWarning() << QString("Core::sendAllFileData: Nothing to read from file: %1").arg(file->file->errorString());
|
||||
delete[] data;
|
||||
file->sendTimer->start(TOX_FILE_INTERVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (transSettings->call_type == TypeVideo)
|
||||
if (tox_file_send_data(core->tox, file->friendId, file->fileNum, data, readSize) == -1)
|
||||
{
|
||||
qDebug() << QString("Core: AV invite from %1 with video").arg(friendId);
|
||||
emit static_cast<Core*>(core)->avInvite(friendId, call_index, true);
|
||||
//qWarning("Core::fileHeartbeat: Error sending data chunk");
|
||||
//core->process();
|
||||
delete[] data;
|
||||
QThread::msleep(1);
|
||||
file->sendTimer->start(TOX_FILE_INTERVAL);
|
||||
return;
|
||||
}
|
||||
delete[] data;
|
||||
file->bytesSent += readSize;
|
||||
//qDebug() << QString("Core::fileHeartbeat: sent %1/%2 bytes").arg(file->bytesSent).arg(file->fileData.size());
|
||||
|
||||
if (file->bytesSent < file->filesize)
|
||||
{
|
||||
file->sendTimer->start(TOX_FILE_INTERVAL);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << QString("Core: AV invite from %1 without video").arg(friendId);
|
||||
emit static_cast<Core*>(core)->avInvite(friendId, call_index, false);
|
||||
qDebug("Core: File transfer finished");
|
||||
file->sendTimer->disconnect();
|
||||
delete file->sendTimer;
|
||||
file->sendTimer = nullptr;
|
||||
tox_file_send_control(core->tox, file->friendId, 0, file->fileNum, TOX_FILECONTROL_FINISHED, nullptr, 0);
|
||||
emit core->fileTransferFinished(*file);
|
||||
}
|
||||
|
||||
delete transSettings;
|
||||
}
|
||||
|
||||
void Core::onAvStart(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV start";
|
||||
return;
|
||||
}
|
||||
|
||||
ToxAvCSettings* transSettings = new ToxAvCSettings;
|
||||
int err = toxav_get_peer_csettings(toxav, call_index, 0, transSettings);
|
||||
if (err != ErrorNone)
|
||||
{
|
||||
qWarning() << "Core::onAvStart: error getting call type";
|
||||
delete transSettings;
|
||||
return;
|
||||
}
|
||||
|
||||
if (transSettings->call_type == TypeVideo)
|
||||
{
|
||||
qDebug() << QString("Core: AV start from %1 with video").arg(friendId);
|
||||
prepareCall(friendId, call_index, toxav, true);
|
||||
emit static_cast<Core*>(core)->avStart(friendId, call_index, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << QString("Core: AV start from %1 without video").arg(friendId);
|
||||
prepareCall(friendId, call_index, toxav, false);
|
||||
emit static_cast<Core*>(core)->avStart(friendId, call_index, false);
|
||||
}
|
||||
|
||||
delete transSettings;
|
||||
}
|
||||
|
||||
void Core::onAvCancel(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV cancel";
|
||||
return;
|
||||
}
|
||||
qDebug() << QString("Core: AV cancel from %1").arg(friendId);
|
||||
|
||||
emit static_cast<Core*>(core)->avCancel(friendId, call_index);
|
||||
}
|
||||
|
||||
void Core::onAvReject(void*, int32_t, void*)
|
||||
{
|
||||
qDebug() << "Core: AV reject";
|
||||
}
|
||||
|
||||
void Core::onAvEnd(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV end";
|
||||
return;
|
||||
}
|
||||
qDebug() << QString("Core: AV end from %1").arg(friendId);
|
||||
|
||||
cleanupCall(call_index);
|
||||
|
||||
emit static_cast<Core*>(core)->avEnd(friendId, call_index);
|
||||
}
|
||||
|
||||
void Core::onAvRinging(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV ringing";
|
||||
return;
|
||||
}
|
||||
|
||||
if (calls[call_index].videoEnabled)
|
||||
{
|
||||
qDebug() << QString("Core: AV ringing with %1 with video").arg(friendId);
|
||||
emit static_cast<Core*>(core)->avRinging(friendId, call_index, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << QString("Core: AV ringing with %1 without video").arg(friendId);
|
||||
emit static_cast<Core*>(core)->avRinging(friendId, call_index, false);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::onAvStarting(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV starting";
|
||||
return;
|
||||
}
|
||||
|
||||
ToxAvCSettings* transSettings = new ToxAvCSettings;
|
||||
int err = toxav_get_peer_csettings(toxav, call_index, 0, transSettings);
|
||||
if (err != ErrorNone)
|
||||
{
|
||||
qWarning() << "Core::onAvStarting: error getting call type";
|
||||
delete transSettings;
|
||||
return;
|
||||
}
|
||||
|
||||
if (transSettings->call_type == TypeVideo)
|
||||
{
|
||||
qDebug() << QString("Core: AV starting from %1 with video").arg(friendId);
|
||||
prepareCall(friendId, call_index, toxav, true);
|
||||
emit static_cast<Core*>(core)->avStarting(friendId, call_index, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << QString("Core: AV starting from %1 without video").arg(friendId);
|
||||
prepareCall(friendId, call_index, toxav, false);
|
||||
emit static_cast<Core*>(core)->avStarting(friendId, call_index, false);
|
||||
}
|
||||
|
||||
delete transSettings;
|
||||
}
|
||||
|
||||
void Core::onAvEnding(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV ending";
|
||||
return;
|
||||
}
|
||||
qDebug() << QString("Core: AV ending from %1").arg(friendId);
|
||||
|
||||
cleanupCall(call_index);
|
||||
|
||||
emit static_cast<Core*>(core)->avEnding(friendId, call_index);
|
||||
}
|
||||
|
||||
void Core::onAvRequestTimeout(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV request timeout";
|
||||
return;
|
||||
}
|
||||
qDebug() << QString("Core: AV request timeout with %1").arg(friendId);
|
||||
|
||||
cleanupCall(call_index);
|
||||
|
||||
emit static_cast<Core*>(core)->avRequestTimeout(friendId, call_index);
|
||||
}
|
||||
|
||||
void Core::onAvPeerTimeout(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV peer timeout";
|
||||
return;
|
||||
}
|
||||
qDebug() << QString("Core: AV peer timeout with %1").arg(friendId);
|
||||
|
||||
cleanupCall(call_index);
|
||||
|
||||
emit static_cast<Core*>(core)->avPeerTimeout(friendId, call_index);
|
||||
}
|
||||
|
||||
void Core::onAvMediaChange(void*, int32_t, void*)
|
||||
{
|
||||
// HALP, PLS COMPLETE MEH
|
||||
qWarning() << "If you see this, please complain on GitHub about seeing me! (Don't forget to say what caused me!)";
|
||||
}
|
||||
|
||||
void Core::answerCall(int callId)
|
||||
{
|
||||
int friendId = toxav_get_peer_id(toxav, callId, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV answer peer ID";
|
||||
return;
|
||||
}
|
||||
|
||||
ToxAvCSettings* transSettings = new ToxAvCSettings;
|
||||
int err = toxav_get_peer_csettings(toxav, callId, 0, transSettings);
|
||||
if (err != ErrorNone)
|
||||
{
|
||||
qWarning() << "Core::answerCall: error getting call settings";
|
||||
delete transSettings;
|
||||
return;
|
||||
}
|
||||
|
||||
if (transSettings->call_type == TypeVideo)
|
||||
{
|
||||
qDebug() << QString("Core: answering call %1 with video").arg(callId);
|
||||
toxav_answer(toxav, callId, transSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << QString("Core: answering call %1 without video").arg(callId);
|
||||
toxav_answer(toxav, callId, transSettings);
|
||||
}
|
||||
|
||||
delete transSettings;
|
||||
}
|
||||
|
||||
void Core::hangupCall(int callId)
|
||||
{
|
||||
qDebug() << QString("Core: hanging up call %1").arg(callId);
|
||||
calls[callId].active = false;
|
||||
toxav_hangup(toxav, callId);
|
||||
}
|
||||
|
||||
void Core::startCall(int friendId, bool video)
|
||||
{
|
||||
int callId;
|
||||
ToxAvCSettings cSettings = av_DefaultSettings;
|
||||
cSettings.max_video_width = TOXAV_MAX_VIDEO_WIDTH;
|
||||
cSettings.max_video_height = TOXAV_MAX_VIDEO_HEIGHT;
|
||||
if (video)
|
||||
{
|
||||
qDebug() << QString("Core: Starting new call with %1 with video").arg(friendId);
|
||||
cSettings.call_type = TypeVideo;
|
||||
toxav_call(toxav, &callId, friendId, &cSettings, TOXAV_RINGING_TIME);
|
||||
calls[callId].videoEnabled=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << QString("Core: Starting new call with %1 without video").arg(friendId);
|
||||
cSettings.call_type = TypeAudio;
|
||||
toxav_call(toxav, &callId, friendId, &cSettings, TOXAV_RINGING_TIME);
|
||||
calls[callId].videoEnabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
void Core::cancelCall(int callId, int friendId)
|
||||
{
|
||||
qDebug() << QString("Core: Cancelling call with %1").arg(friendId);
|
||||
calls[callId].active = false;
|
||||
toxav_cancel(toxav, callId, friendId, 0);
|
||||
}
|
||||
|
||||
void Core::prepareCall(int friendId, int callId, ToxAv* toxav, bool videoEnabled)
|
||||
{
|
||||
qDebug() << QString("Core: preparing call %1").arg(callId);
|
||||
calls[callId].callId = callId;
|
||||
calls[callId].friendId = friendId;
|
||||
// the following three lines are also now redundant from startCall, but are
|
||||
// necessary there for outbound and here for inbound
|
||||
calls[callId].codecSettings = av_DefaultSettings;
|
||||
calls[callId].codecSettings.max_video_width = TOXAV_MAX_VIDEO_WIDTH;
|
||||
calls[callId].codecSettings.max_video_height = TOXAV_MAX_VIDEO_HEIGHT;
|
||||
calls[callId].videoEnabled = videoEnabled;
|
||||
toxav_prepare_transmission(toxav, callId, av_jbufdc, av_VADd, videoEnabled);
|
||||
|
||||
// Prepare output
|
||||
QAudioFormat format;
|
||||
format.setSampleRate(calls[callId].codecSettings.audio_sample_rate);
|
||||
format.setChannelCount(calls[callId].codecSettings.audio_channels);
|
||||
format.setSampleSize(16);
|
||||
format.setCodec("audio/pcm");
|
||||
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||
format.setSampleType(QAudioFormat::SignedInt);
|
||||
if (!QAudioDeviceInfo::defaultOutputDevice().isFormatSupported(format))
|
||||
{
|
||||
calls[callId].audioOutput = nullptr;
|
||||
qWarning() << "Core: Raw audio format not supported by output backend, cannot play audio.";
|
||||
}
|
||||
else if (calls[callId].audioOutput==nullptr)
|
||||
{
|
||||
calls[callId].audioOutput = new QAudioOutput(format);
|
||||
calls[callId].audioOutput->setBufferSize(1900*30); // Make this bigger to get less underflows, but more latency
|
||||
calls[callId].audioOutput->start(&calls[callId].audioBuffer);
|
||||
int error = calls[callId].audioOutput->error();
|
||||
if (error != QAudio::NoError)
|
||||
{
|
||||
qWarning() << QString("Core: Error %1 when starting audio output").arg(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Start input
|
||||
if (!QAudioDeviceInfo::defaultInputDevice().isFormatSupported(format))
|
||||
{
|
||||
calls[callId].audioInput = nullptr;
|
||||
qWarning() << "Default input format not supported, cannot record audio";
|
||||
}
|
||||
else if (calls[callId].audioInput==nullptr)
|
||||
{
|
||||
calls[callId].audioInput = new QAudioInput(format);
|
||||
calls[callId].audioInputDevice = calls[callId].audioInput->start();
|
||||
}
|
||||
|
||||
// Go
|
||||
calls[callId].active = true;
|
||||
|
||||
if (calls[callId].audioInput != nullptr)
|
||||
{
|
||||
calls[callId].sendAudioTimer->setInterval(2);
|
||||
calls[callId].sendAudioTimer->setSingleShot(true);
|
||||
connect(calls[callId].sendAudioTimer, &QTimer::timeout, [=](){sendCallAudio(callId,toxav);});
|
||||
calls[callId].sendAudioTimer->start();
|
||||
}
|
||||
|
||||
if (calls[callId].videoEnabled)
|
||||
{
|
||||
calls[callId].sendVideoTimer->setInterval(50);
|
||||
calls[callId].sendVideoTimer->setSingleShot(true);
|
||||
calls[callId].sendVideoTimer->start();
|
||||
|
||||
Widget::getInstance()->getCamera()->suscribe();
|
||||
}
|
||||
else if (calls[callId].audioInput == nullptr && calls[callId].audioOutput == nullptr)
|
||||
{
|
||||
qWarning() << "Audio only call can neither play nor record audio, killing call";
|
||||
toxav_hangup(toxav, callId);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::cleanupCall(int callId)
|
||||
{
|
||||
qDebug() << QString("Core: cleaning up call %1").arg(callId);
|
||||
calls[callId].active = false;
|
||||
disconnect(calls[callId].sendAudioTimer,0,0,0);
|
||||
calls[callId].sendAudioTimer->stop();
|
||||
calls[callId].sendVideoTimer->stop();
|
||||
if (calls[callId].audioOutput != nullptr)
|
||||
{
|
||||
calls[callId].audioOutput->stop();
|
||||
}
|
||||
if (calls[callId].audioInput != nullptr)
|
||||
{
|
||||
calls[callId].audioInput->stop();
|
||||
}
|
||||
if (calls[callId].videoEnabled)
|
||||
Widget::getInstance()->getCamera()->unsuscribe();
|
||||
calls[callId].audioBuffer.clear();
|
||||
}
|
||||
|
||||
void Core::playCallAudio(ToxAv*, int32_t callId, int16_t *data, int length, void *user_data)
|
||||
{
|
||||
Q_UNUSED(user_data);
|
||||
|
||||
if (!calls[callId].active || calls[callId].audioOutput == nullptr)
|
||||
return;
|
||||
calls[callId].audioBuffer.write((char*)data, length*2);
|
||||
int state = calls[callId].audioOutput->state();
|
||||
if (state != QAudio::ActiveState)
|
||||
{
|
||||
qDebug() << QString("Core: Audio state is %1").arg(state);
|
||||
calls[callId].audioOutput->start(&calls[callId].audioBuffer);
|
||||
}
|
||||
int error = calls[callId].audioOutput->error();
|
||||
if (error != QAudio::NoError)
|
||||
qWarning() << QString("Core::playCallAudio: Error: %1").arg(error);
|
||||
}
|
||||
|
||||
void Core::sendCallAudio(int callId, ToxAv* toxav)
|
||||
{
|
||||
if (!calls[callId].active || calls[callId].audioInput == nullptr)
|
||||
return;
|
||||
int framesize = (calls[callId].codecSettings.audio_frame_duration * calls[callId].codecSettings.audio_sample_rate) / 1000;
|
||||
uint8_t buf[framesize*2], dest[framesize*2];
|
||||
int bytesReady = calls[callId].audioInput->bytesReady();
|
||||
if (bytesReady >= framesize*2)
|
||||
{
|
||||
calls[callId].audioInputDevice->read((char*)buf, framesize*2);
|
||||
int result = toxav_prepare_audio_frame(toxav, callId, dest, framesize*2, (int16_t*)buf, framesize);
|
||||
if (result < 0)
|
||||
{
|
||||
qWarning() << QString("Core: Unable to prepare audio frame, error %1").arg(result);
|
||||
calls[callId].sendAudioTimer->start();
|
||||
return;
|
||||
}
|
||||
result = toxav_send_audio(toxav, callId, dest, result);
|
||||
if (result < 0)
|
||||
{
|
||||
qWarning() << QString("Core: Unable to send audio frame, error %1").arg(result);
|
||||
calls[callId].sendAudioTimer->start();
|
||||
return;
|
||||
}
|
||||
calls[callId].sendAudioTimer->start();
|
||||
}
|
||||
else
|
||||
calls[callId].sendAudioTimer->start();
|
||||
}
|
||||
|
||||
void Core::playCallVideo(ToxAv*, int32_t callId, vpx_image_t* img, void *user_data)
|
||||
{
|
||||
Q_UNUSED(user_data);
|
||||
|
||||
if (!calls[callId].active || !calls[callId].videoEnabled)
|
||||
return;
|
||||
|
||||
if (videoBusyness >= 1)
|
||||
qWarning() << "Core: playCallVideo: Busy, dropping current frame";
|
||||
else
|
||||
emit Widget::getInstance()->getCore()->videoFrameReceived(img);
|
||||
vpx_img_free(img);
|
||||
}
|
||||
|
||||
void Core::sendCallVideo(int callId)
|
||||
{
|
||||
if (!calls[callId].active || !calls[callId].videoEnabled)
|
||||
return;
|
||||
|
||||
vpx_image frame = camera->getLastVPXImage();
|
||||
if (frame.w && frame.h)
|
||||
{
|
||||
int result;
|
||||
if((result = toxav_prepare_video_frame(toxav, callId, videobuf, videobufsize, &frame)) < 0)
|
||||
{
|
||||
qDebug() << QString("Core: toxav_prepare_video_frame: error %1").arg(result);
|
||||
vpx_img_free(&frame);
|
||||
calls[callId].sendVideoTimer->start();
|
||||
return;
|
||||
}
|
||||
|
||||
if((result = toxav_send_video(toxav, callId, (uint8_t*)videobuf, result)) < 0)
|
||||
qDebug() << QString("Core: toxav_send_video error: %1").arg(result);
|
||||
|
||||
vpx_img_free(&frame);
|
||||
}
|
||||
else
|
||||
qDebug("Core::sendCallVideo: Invalid frame (bad camera ?)");
|
||||
|
||||
calls[callId].sendVideoTimer->start();
|
||||
}
|
||||
|
||||
void Core::groupInviteFriend(int friendId, int groupId)
|
||||
|
@ -1511,21 +1045,3 @@ void Core::createGroup()
|
|||
{
|
||||
emit emptyGroupCreated(tox_add_groupchat(tox));
|
||||
}
|
||||
|
||||
void Core::increaseVideoBusyness()
|
||||
{
|
||||
videoBusyness++;
|
||||
}
|
||||
|
||||
void Core::decreaseVideoBusyness()
|
||||
{
|
||||
videoBusyness--;
|
||||
}
|
||||
|
||||
void Core::micMuteToggle(int callId)
|
||||
{
|
||||
if (calls[callId].audioInput->state() == QAudio::ActiveState)
|
||||
calls[callId].audioInput->suspend();
|
||||
else
|
||||
calls[callId].audioInput->start();
|
||||
}
|
||||
|
|
22
core.h
22
core.h
|
@ -17,11 +17,12 @@
|
|||
#ifndef CORE_HPP
|
||||
#define CORE_HPP
|
||||
|
||||
#include "audiobuffer.h"
|
||||
|
||||
#include <tox/tox.h>
|
||||
#include <tox/toxav.h>
|
||||
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
|
@ -38,7 +39,7 @@
|
|||
#define TOXAV_MAX_CALLS 16
|
||||
#define GROUPCHAT_MAX_SIZE 32
|
||||
#define TOX_SAVE_INTERVAL 30*1000
|
||||
#define TOX_FILE_INTERVAL 20
|
||||
#define TOX_FILE_INTERVAL 1
|
||||
#define TOX_BOOTSTRAP_INTERVAL 10*1000
|
||||
#define TOXAV_RINGING_TIME 15
|
||||
|
||||
|
@ -90,22 +91,22 @@ struct ToxFile
|
|||
long long filesize;
|
||||
FileStatus status;
|
||||
FileDirection direction;
|
||||
QFuture<void> sendFuture;
|
||||
QTimer* sendTimer;
|
||||
};
|
||||
|
||||
struct ToxCall
|
||||
{
|
||||
public:
|
||||
AudioBuffer audioBuffer;
|
||||
QAudioOutput* audioOutput;
|
||||
QAudioInput* audioInput;
|
||||
QIODevice* audioInputDevice;
|
||||
ToxAvCSettings codecSettings;
|
||||
QTimer *sendAudioTimer, *sendVideoTimer;
|
||||
int callId;
|
||||
int friendId;
|
||||
bool videoEnabled;
|
||||
bool active;
|
||||
bool muteMic;
|
||||
ALCdevice* alOutDev, *alInDev;
|
||||
ALCcontext* alContext;
|
||||
ALuint alSource;
|
||||
};
|
||||
|
||||
class Core : public QObject
|
||||
|
@ -268,8 +269,9 @@ private:
|
|||
|
||||
static void prepareCall(int friendId, int callId, ToxAv *toxav, bool videoEnabled);
|
||||
static void cleanupCall(int callId);
|
||||
static void playCallAudio(ToxAv *toxav, int32_t callId, int16_t *data, int length, void *user_data); // Callback
|
||||
static void playCallAudio(ToxAv *toxav, int32_t callId, int16_t *data, int samples, void *user_data); // Callback
|
||||
static void sendCallAudio(int callId, ToxAv* toxav);
|
||||
static void playAudioBuffer(int callId, int16_t *data, int samples, unsigned channels, int sampleRate);
|
||||
static void playCallVideo(ToxAv* toxav, int32_t callId, vpx_image_t* img, void *user_data);
|
||||
void sendCallVideo(int callId);
|
||||
|
||||
|
@ -278,8 +280,8 @@ private:
|
|||
|
||||
void loadConfiguration();
|
||||
void loadFriends();
|
||||
static void sendAllFileData(Core* core, ToxFile* file);
|
||||
|
||||
static void sendAllFileData(Core* core, ToxFile* file);
|
||||
static void removeFileFromQueue(bool sendQueue, int friendId, int fileId);
|
||||
|
||||
void checkLastOnline(int friendId);
|
||||
|
|
526
coreav.cpp
Normal file
526
coreav.cpp
Normal file
|
@ -0,0 +1,526 @@
|
|||
#include "core.h"
|
||||
#include "widget/widget.h"
|
||||
|
||||
ToxCall Core::calls[TOXAV_MAX_CALLS];
|
||||
const int Core::videobufsize{TOXAV_MAX_VIDEO_WIDTH * TOXAV_MAX_VIDEO_HEIGHT * 4};
|
||||
uint8_t* Core::videobuf;
|
||||
int Core::videoBusyness;
|
||||
|
||||
void Core::prepareCall(int friendId, int callId, ToxAv* toxav, bool videoEnabled)
|
||||
{
|
||||
qDebug() << QString("Core: preparing call %1").arg(callId);
|
||||
calls[callId].callId = callId;
|
||||
calls[callId].friendId = friendId;
|
||||
calls[callId].muteMic = false;
|
||||
// the following three lines are also now redundant from startCall, but are
|
||||
// necessary there for outbound and here for inbound
|
||||
calls[callId].codecSettings = av_DefaultSettings;
|
||||
calls[callId].codecSettings.max_video_width = TOXAV_MAX_VIDEO_WIDTH;
|
||||
calls[callId].codecSettings.max_video_height = TOXAV_MAX_VIDEO_HEIGHT;
|
||||
calls[callId].videoEnabled = videoEnabled;
|
||||
toxav_prepare_transmission(toxav, callId, av_jbufdc, av_VADd, videoEnabled);
|
||||
|
||||
// Audio output
|
||||
calls[callId].alOutDev = alcOpenDevice(nullptr);
|
||||
if (!calls[callId].alOutDev)
|
||||
{
|
||||
qWarning() << "Coreav: Cannot open output audio device, hanging up call";
|
||||
toxav_hangup(toxav, callId);
|
||||
return;
|
||||
}
|
||||
calls[callId].alContext=alcCreateContext(calls[callId].alOutDev,nullptr);
|
||||
if (!alcMakeContextCurrent(calls[callId].alContext))
|
||||
{
|
||||
qWarning() << "Coreav: Cannot create output audio context, hanging up call";
|
||||
alcCloseDevice(calls[callId].alOutDev);
|
||||
toxav_hangup(toxav, callId);
|
||||
return;
|
||||
}
|
||||
alGenSources(1, &calls[callId].alSource);
|
||||
|
||||
// Audio Input
|
||||
calls[callId].alInDev = alcCaptureOpenDevice(NULL,av_DefaultSettings.audio_sample_rate, AL_FORMAT_MONO16, (av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4) / 1000);
|
||||
if (!calls[callId].alInDev)
|
||||
{
|
||||
qWarning() << "Coreav: Cannot open input audio device, hanging up call";
|
||||
toxav_hangup(toxav, callId);
|
||||
return;
|
||||
}
|
||||
alcCaptureStart(calls[callId].alInDev);
|
||||
|
||||
// Go
|
||||
calls[callId].active = true;
|
||||
calls[callId].sendAudioTimer->setInterval(5);
|
||||
calls[callId].sendAudioTimer->setSingleShot(true);
|
||||
connect(calls[callId].sendAudioTimer, &QTimer::timeout, [=](){sendCallAudio(callId,toxav);});
|
||||
calls[callId].sendAudioTimer->start();
|
||||
if (calls[callId].videoEnabled)
|
||||
{
|
||||
calls[callId].sendVideoTimer->setInterval(50);
|
||||
calls[callId].sendVideoTimer->setSingleShot(true);
|
||||
calls[callId].sendVideoTimer->start();
|
||||
Widget::getInstance()->getCamera()->suscribe();
|
||||
}
|
||||
}
|
||||
|
||||
void Core::onAvMediaChange(void*, int32_t, void*)
|
||||
{
|
||||
// HALP, PLS COMPLETE MEH
|
||||
qWarning() << "If you see this, please complain on GitHub about seeing me! (Don't forget to say what caused me!)";
|
||||
}
|
||||
|
||||
void Core::answerCall(int callId)
|
||||
{
|
||||
int friendId = toxav_get_peer_id(toxav, callId, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV answer peer ID";
|
||||
return;
|
||||
}
|
||||
|
||||
ToxAvCSettings* transSettings = new ToxAvCSettings;
|
||||
int err = toxav_get_peer_csettings(toxav, callId, 0, transSettings);
|
||||
if (err != ErrorNone)
|
||||
{
|
||||
qWarning() << "Core::answerCall: error getting call settings";
|
||||
delete transSettings;
|
||||
return;
|
||||
}
|
||||
|
||||
if (transSettings->call_type == TypeVideo)
|
||||
{
|
||||
qDebug() << QString("Core: answering call %1 with video").arg(callId);
|
||||
toxav_answer(toxav, callId, transSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << QString("Core: answering call %1 without video").arg(callId);
|
||||
toxav_answer(toxav, callId, transSettings);
|
||||
}
|
||||
|
||||
delete transSettings;
|
||||
}
|
||||
|
||||
void Core::hangupCall(int callId)
|
||||
{
|
||||
qDebug() << QString("Core: hanging up call %1").arg(callId);
|
||||
calls[callId].active = false;
|
||||
toxav_hangup(toxav, callId);
|
||||
}
|
||||
|
||||
void Core::startCall(int friendId, bool video)
|
||||
{
|
||||
int callId;
|
||||
ToxAvCSettings cSettings = av_DefaultSettings;
|
||||
cSettings.max_video_width = TOXAV_MAX_VIDEO_WIDTH;
|
||||
cSettings.max_video_height = TOXAV_MAX_VIDEO_HEIGHT;
|
||||
if (video)
|
||||
{
|
||||
qDebug() << QString("Core: Starting new call with %1 with video").arg(friendId);
|
||||
cSettings.call_type = TypeVideo;
|
||||
toxav_call(toxav, &callId, friendId, &cSettings, TOXAV_RINGING_TIME);
|
||||
calls[callId].videoEnabled=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << QString("Core: Starting new call with %1 without video").arg(friendId);
|
||||
cSettings.call_type = TypeAudio;
|
||||
toxav_call(toxav, &callId, friendId, &cSettings, TOXAV_RINGING_TIME);
|
||||
calls[callId].videoEnabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
void Core::cancelCall(int callId, int friendId)
|
||||
{
|
||||
qDebug() << QString("Core: Cancelling call with %1").arg(friendId);
|
||||
calls[callId].active = false;
|
||||
toxav_cancel(toxav, callId, friendId, 0);
|
||||
}
|
||||
|
||||
void Core::cleanupCall(int callId)
|
||||
{
|
||||
qDebug() << QString("Core: cleaning up call %1").arg(callId);
|
||||
calls[callId].active = false;
|
||||
disconnect(calls[callId].sendAudioTimer,0,0,0);
|
||||
calls[callId].sendAudioTimer->stop();
|
||||
calls[callId].sendVideoTimer->stop();
|
||||
if (calls[callId].videoEnabled)
|
||||
Widget::getInstance()->getCamera()->unsuscribe();
|
||||
alcMakeContextCurrent(nullptr);
|
||||
alcDestroyContext(calls[callId].alContext);
|
||||
alcCloseDevice(calls[callId].alOutDev);
|
||||
alcCaptureStop(calls[callId].alInDev);
|
||||
alcCaptureCloseDevice(calls[callId].alInDev);
|
||||
}
|
||||
|
||||
void Core::playCallAudio(ToxAv* toxav, int32_t callId, int16_t *data, int samples, void *user_data)
|
||||
{
|
||||
Q_UNUSED(user_data);
|
||||
|
||||
if (!calls[callId].active)
|
||||
return;
|
||||
|
||||
ToxAvCSettings dest;
|
||||
if(toxav_get_peer_csettings(toxav, callId, 0, &dest) == 0)
|
||||
playAudioBuffer(callId, data, samples, dest.audio_channels, dest.audio_sample_rate);
|
||||
}
|
||||
|
||||
void Core::sendCallAudio(int callId, ToxAv* toxav)
|
||||
{
|
||||
if (!calls[callId].active)
|
||||
return;
|
||||
|
||||
if (calls[callId].muteMic)
|
||||
{
|
||||
calls[callId].sendAudioTimer->start();
|
||||
return;
|
||||
}
|
||||
|
||||
int framesize = (calls[callId].codecSettings.audio_frame_duration * calls[callId].codecSettings.audio_sample_rate) / 1000;
|
||||
uint8_t buf[framesize*2], dest[framesize*2];
|
||||
|
||||
bool frame = false;
|
||||
ALint samples;
|
||||
alcGetIntegerv(calls[callId].alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
|
||||
if(samples >= framesize)
|
||||
{
|
||||
alcCaptureSamples(calls[callId].alInDev, buf, framesize);
|
||||
frame = 1;
|
||||
}
|
||||
|
||||
if(frame)
|
||||
{
|
||||
int r;
|
||||
if((r = toxav_prepare_audio_frame(toxav, callId, dest, framesize*2, (int16_t*)buf, framesize)) < 0)
|
||||
{
|
||||
qDebug() << "Core: toxav_prepare_audio_frame error";
|
||||
calls[callId].sendAudioTimer->start();
|
||||
return;
|
||||
}
|
||||
|
||||
if((r = toxav_send_audio(toxav, callId, dest, r)) < 0)
|
||||
qDebug() << "Core: toxav_send_audio error";
|
||||
}
|
||||
calls[callId].sendAudioTimer->start();
|
||||
}
|
||||
|
||||
void Core::playCallVideo(ToxAv*, int32_t callId, vpx_image_t* img, void *user_data)
|
||||
{
|
||||
Q_UNUSED(user_data);
|
||||
|
||||
if (!calls[callId].active || !calls[callId].videoEnabled)
|
||||
return;
|
||||
|
||||
if (videoBusyness >= 1)
|
||||
qWarning() << "Core: playCallVideo: Busy, dropping current frame";
|
||||
else
|
||||
emit Widget::getInstance()->getCore()->videoFrameReceived(img);
|
||||
vpx_img_free(img);
|
||||
}
|
||||
|
||||
void Core::sendCallVideo(int callId)
|
||||
{
|
||||
if (!calls[callId].active || !calls[callId].videoEnabled)
|
||||
return;
|
||||
|
||||
vpx_image frame = camera->getLastVPXImage();
|
||||
if (frame.w && frame.h)
|
||||
{
|
||||
int result;
|
||||
if((result = toxav_prepare_video_frame(toxav, callId, videobuf, videobufsize, &frame)) < 0)
|
||||
{
|
||||
qDebug() << QString("Core: toxav_prepare_video_frame: error %1").arg(result);
|
||||
vpx_img_free(&frame);
|
||||
calls[callId].sendVideoTimer->start();
|
||||
return;
|
||||
}
|
||||
|
||||
if((result = toxav_send_video(toxav, callId, (uint8_t*)videobuf, result)) < 0)
|
||||
qDebug() << QString("Core: toxav_send_video error: %1").arg(result);
|
||||
|
||||
vpx_img_free(&frame);
|
||||
}
|
||||
else
|
||||
qDebug("Core::sendCallVideo: Invalid frame (bad camera ?)");
|
||||
|
||||
calls[callId].sendVideoTimer->start();
|
||||
}
|
||||
|
||||
|
||||
void Core::increaseVideoBusyness()
|
||||
{
|
||||
videoBusyness++;
|
||||
}
|
||||
|
||||
void Core::decreaseVideoBusyness()
|
||||
{
|
||||
videoBusyness--;
|
||||
}
|
||||
|
||||
void Core::micMuteToggle(int callId)
|
||||
{
|
||||
calls[callId].muteMic = !calls[callId].muteMic;
|
||||
}
|
||||
|
||||
void Core::onAvCancel(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV cancel";
|
||||
return;
|
||||
}
|
||||
qDebug() << QString("Core: AV cancel from %1").arg(friendId);
|
||||
|
||||
emit static_cast<Core*>(core)->avCancel(friendId, call_index);
|
||||
}
|
||||
|
||||
void Core::onAvReject(void*, int32_t, void*)
|
||||
{
|
||||
qDebug() << "Core: AV reject";
|
||||
}
|
||||
|
||||
void Core::onAvEnd(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV end";
|
||||
return;
|
||||
}
|
||||
qDebug() << QString("Core: AV end from %1").arg(friendId);
|
||||
|
||||
cleanupCall(call_index);
|
||||
|
||||
emit static_cast<Core*>(core)->avEnd(friendId, call_index);
|
||||
}
|
||||
|
||||
void Core::onAvRinging(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV ringing";
|
||||
return;
|
||||
}
|
||||
|
||||
if (calls[call_index].videoEnabled)
|
||||
{
|
||||
qDebug() << QString("Core: AV ringing with %1 with video").arg(friendId);
|
||||
emit static_cast<Core*>(core)->avRinging(friendId, call_index, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << QString("Core: AV ringing with %1 without video").arg(friendId);
|
||||
emit static_cast<Core*>(core)->avRinging(friendId, call_index, false);
|
||||
}
|
||||
}
|
||||
|
||||
void Core::onAvStarting(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV starting";
|
||||
return;
|
||||
}
|
||||
|
||||
ToxAvCSettings* transSettings = new ToxAvCSettings;
|
||||
int err = toxav_get_peer_csettings(toxav, call_index, 0, transSettings);
|
||||
if (err != ErrorNone)
|
||||
{
|
||||
qWarning() << "Core::onAvStarting: error getting call type";
|
||||
delete transSettings;
|
||||
return;
|
||||
}
|
||||
|
||||
if (transSettings->call_type == TypeVideo)
|
||||
{
|
||||
qDebug() << QString("Core: AV starting from %1 with video").arg(friendId);
|
||||
prepareCall(friendId, call_index, toxav, true);
|
||||
emit static_cast<Core*>(core)->avStarting(friendId, call_index, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << QString("Core: AV starting from %1 without video").arg(friendId);
|
||||
prepareCall(friendId, call_index, toxav, false);
|
||||
emit static_cast<Core*>(core)->avStarting(friendId, call_index, false);
|
||||
}
|
||||
|
||||
delete transSettings;
|
||||
}
|
||||
|
||||
void Core::onAvEnding(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV ending";
|
||||
return;
|
||||
}
|
||||
qDebug() << QString("Core: AV ending from %1").arg(friendId);
|
||||
|
||||
cleanupCall(call_index);
|
||||
|
||||
emit static_cast<Core*>(core)->avEnding(friendId, call_index);
|
||||
}
|
||||
|
||||
void Core::onAvRequestTimeout(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV request timeout";
|
||||
return;
|
||||
}
|
||||
qDebug() << QString("Core: AV request timeout with %1").arg(friendId);
|
||||
|
||||
cleanupCall(call_index);
|
||||
|
||||
emit static_cast<Core*>(core)->avRequestTimeout(friendId, call_index);
|
||||
}
|
||||
|
||||
void Core::onAvPeerTimeout(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV peer timeout";
|
||||
return;
|
||||
}
|
||||
qDebug() << QString("Core: AV peer timeout with %1").arg(friendId);
|
||||
|
||||
cleanupCall(call_index);
|
||||
|
||||
emit static_cast<Core*>(core)->avPeerTimeout(friendId, call_index);
|
||||
}
|
||||
|
||||
|
||||
void Core::onAvInvite(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV invite";
|
||||
return;
|
||||
}
|
||||
|
||||
ToxAvCSettings* transSettings = new ToxAvCSettings;
|
||||
int err = toxav_get_peer_csettings(toxav, call_index, 0, transSettings);
|
||||
if (err != ErrorNone)
|
||||
{
|
||||
qWarning() << "Core::onAvInvite: error getting call type";
|
||||
delete transSettings;
|
||||
return;
|
||||
}
|
||||
|
||||
if (transSettings->call_type == TypeVideo)
|
||||
{
|
||||
qDebug() << QString("Core: AV invite from %1 with video").arg(friendId);
|
||||
emit static_cast<Core*>(core)->avInvite(friendId, call_index, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << QString("Core: AV invite from %1 without video").arg(friendId);
|
||||
emit static_cast<Core*>(core)->avInvite(friendId, call_index, false);
|
||||
}
|
||||
|
||||
delete transSettings;
|
||||
}
|
||||
|
||||
void Core::onAvStart(void* _toxav, int32_t call_index, void* core)
|
||||
{
|
||||
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
|
||||
|
||||
int friendId = toxav_get_peer_id(toxav, call_index, 0);
|
||||
if (friendId < 0)
|
||||
{
|
||||
qWarning() << "Core: Received invalid AV start";
|
||||
return;
|
||||
}
|
||||
|
||||
ToxAvCSettings* transSettings = new ToxAvCSettings;
|
||||
int err = toxav_get_peer_csettings(toxav, call_index, 0, transSettings);
|
||||
if (err != ErrorNone)
|
||||
{
|
||||
qWarning() << "Core::onAvStart: error getting call type";
|
||||
delete transSettings;
|
||||
return;
|
||||
}
|
||||
|
||||
if (transSettings->call_type == TypeVideo)
|
||||
{
|
||||
qDebug() << QString("Core: AV start from %1 with video").arg(friendId);
|
||||
prepareCall(friendId, call_index, toxav, true);
|
||||
emit static_cast<Core*>(core)->avStart(friendId, call_index, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << QString("Core: AV start from %1 without video").arg(friendId);
|
||||
prepareCall(friendId, call_index, toxav, false);
|
||||
emit static_cast<Core*>(core)->avStart(friendId, call_index, false);
|
||||
}
|
||||
|
||||
delete transSettings;
|
||||
}
|
||||
|
||||
// This function's logic was shamelessly stolen from uTox
|
||||
void Core::playAudioBuffer(int callId, int16_t *data, int samples, unsigned channels, int sampleRate)
|
||||
{
|
||||
if(!channels || channels > 2)
|
||||
{
|
||||
qWarning() << "Core::playAudioBuffer: trying to play on "<<channels<<" channels! Giving up.";
|
||||
return;
|
||||
}
|
||||
|
||||
ALuint bufid;
|
||||
ALint processed, queued;
|
||||
alGetSourcei(calls[callId].alSource, AL_BUFFERS_PROCESSED, &processed);
|
||||
alGetSourcei(calls[callId].alSource, AL_BUFFERS_QUEUED, &queued);
|
||||
alSourcei(calls[callId].alSource, AL_LOOPING, AL_FALSE);
|
||||
|
||||
if(processed)
|
||||
{
|
||||
ALuint bufids[processed];
|
||||
alSourceUnqueueBuffers(calls[callId].alSource, processed, bufids);
|
||||
alDeleteBuffers(processed - 1, bufids + 1);
|
||||
bufid = bufids[0];
|
||||
}
|
||||
else if(queued < 16)
|
||||
{
|
||||
alGenBuffers(1, &bufid);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Core: Dropped audio frame";
|
||||
return;
|
||||
}
|
||||
|
||||
alBufferData(bufid, (channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, data,
|
||||
samples * 2 * channels, sampleRate);
|
||||
alSourceQueueBuffers(calls[callId].alSource, 1, &bufid);
|
||||
|
||||
ALint state;
|
||||
alGetSourcei(calls[callId].alSource, AL_SOURCE_STATE, &state);
|
||||
if(state != AL_PLAYING)
|
||||
{
|
||||
alSourcePlay(calls[callId].alSource);
|
||||
qDebug() << "Core: Starting audio source of call " << callId;
|
||||
}
|
||||
}
|
9
qtox.pro
9
qtox.pro
|
@ -41,9 +41,9 @@ INSTALLS += target
|
|||
|
||||
INCLUDEPATH += libs/include
|
||||
win32 {
|
||||
LIBS += $$PWD/libs/lib/libtoxav.a $$PWD/libs/lib/libopus.a $$PWD/libs/lib/libvpx.a $$PWD/libs/lib/libtoxcore.a -lws2_32 $$PWD/libs/lib/libsodium.a -lpthread -liphlpapi
|
||||
LIBS += $$PWD/libs/lib/libtoxav.a $$PWD/libs/lib/libopus.a $$PWD/libs/lib/libvpx.a $$PWD/libs/lib/libopenal32.a $$PWD/libs/lib/libtoxcore.a -lws2_32 $$PWD/libs/lib/libsodium.a -lpthread -liphlpapi
|
||||
} else {
|
||||
LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -lsodium -lvpx
|
||||
LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -lsodium -lvpx -lopenal
|
||||
}
|
||||
|
||||
#### Static linux build
|
||||
|
@ -79,7 +79,6 @@ HEADERS += widget/form/addfriendform.h \
|
|||
friendlist.h \
|
||||
cdata.h \
|
||||
cstring.h \
|
||||
audiobuffer.h \
|
||||
widget/selfcamview.h \
|
||||
widget/videosurface.h \
|
||||
widget/camera.h \
|
||||
|
@ -117,7 +116,6 @@ SOURCES += \
|
|||
settings.cpp \
|
||||
cdata.cpp \
|
||||
cstring.cpp \
|
||||
audiobuffer.cpp \
|
||||
widget/selfcamview.cpp \
|
||||
widget/videosurface.cpp \
|
||||
widget/camera.cpp \
|
||||
|
@ -128,4 +126,5 @@ SOURCES += \
|
|||
style.cpp \
|
||||
widget/adjustingscrollarea.cpp \
|
||||
widget/croppinglabel.cpp \
|
||||
widget/friendlistwidget.cpp
|
||||
widget/friendlistwidget.cpp \
|
||||
coreav.cpp
|
||||
|
|
|
@ -91,13 +91,13 @@
|
|||
<context>
|
||||
<name>ChatForm</name>
|
||||
<message>
|
||||
<location filename="../widget/form/chatform.cpp" line="282"/>
|
||||
<location filename="../widget/form/chatform.cpp" line="283"/>
|
||||
<source>Send a file</source>
|
||||
<translation>Invia un file</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widget/form/chatform.cpp" line="613"/>
|
||||
<location filename="../widget/form/chatform.cpp" line="619"/>
|
||||
<location filename="../widget/form/chatform.cpp" line="620"/>
|
||||
<location filename="../widget/form/chatform.cpp" line="626"/>
|
||||
<source>Save chat log</source>
|
||||
<translation>Salva il log della chat</translation>
|
||||
</message>
|
||||
|
@ -113,19 +113,19 @@
|
|||
<context>
|
||||
<name>FileTransfertWidget</name>
|
||||
<message>
|
||||
<location filename="../widget/filetransfertwidget.cpp" line="276"/>
|
||||
<location filename="../widget/filetransfertwidget.cpp" line="281"/>
|
||||
<source>Save a file</source>
|
||||
<comment>Title of the file saving dialog</comment>
|
||||
<translation>Salva file</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widget/filetransfertwidget.cpp" line="287"/>
|
||||
<location filename="../widget/filetransfertwidget.cpp" line="292"/>
|
||||
<source>Location not writable</source>
|
||||
<comment>Title of permissions popup</comment>
|
||||
<translation>Errore</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../widget/filetransfertwidget.cpp" line="287"/>
|
||||
<location filename="../widget/filetransfertwidget.cpp" line="292"/>
|
||||
<source>You do not have permission to write that location. Choose another, or cancel the save dialog.</source>
|
||||
<comment>text of permissions popup</comment>
|
||||
<translation>Non hai sufficienti permessi per scrivere in questa locazione. Scegli un'altra posizione, o annulla il salvataggio.</translation>
|
||||
|
|
|
@ -171,10 +171,15 @@ void FileTransfertWidget::onFileTransferInfo(int FriendId, int FileNum, int64_t
|
|||
etaTime = etaTime.addSecs(etaSecs);
|
||||
eta->setText(etaTime.toString("mm:ss"));
|
||||
if (!Filesize)
|
||||
{
|
||||
progress->setValue(0);
|
||||
qDebug() << QString("FT: received %1 bytes of an empty file, stop sending sequential devices, zetok!").arg(BytesSent);
|
||||
}
|
||||
else
|
||||
{
|
||||
progress->setValue(BytesSent*100/Filesize);
|
||||
qDebug() << QString("FT: received %1/%2 bytes, progress is %3%").arg(BytesSent).arg(Filesize).arg(BytesSent*100/Filesize);
|
||||
qDebug() << QString("FT: received %1/%2 bytes, progress is %3%").arg(BytesSent).arg(Filesize).arg(BytesSent*100/Filesize);
|
||||
}
|
||||
lastUpdate = newtime;
|
||||
lastBytesSent = BytesSent;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <QMenu>
|
||||
#include <QWidgetAction>
|
||||
#include <QGridLayout>
|
||||
#include <QMessageBox>
|
||||
|
||||
ChatForm::ChatForm(Friend* chatFriend)
|
||||
: f(chatFriend), curRow{0}, lockSliderToBottom{true}
|
||||
|
@ -286,6 +287,12 @@ void ChatForm::onAttachClicked()
|
|||
QFile file(path);
|
||||
if (!file.exists() || !file.open(QIODevice::ReadOnly))
|
||||
return;
|
||||
if (file.isSequential())
|
||||
{
|
||||
QMessageBox::critical(0, "Bad Idea", "You're trying to send a special (sequential) file, that's not going to work!");
|
||||
return;
|
||||
file.close();
|
||||
}
|
||||
long long filesize = file.size();
|
||||
file.close();
|
||||
QFileInfo fi(path);
|
||||
|
|
|
@ -219,7 +219,9 @@ Widget::~Widget()
|
|||
core->saveConfiguration();
|
||||
instance = nullptr;
|
||||
coreThread->exit();
|
||||
coreThread->wait();
|
||||
coreThread->wait(500); // In case of deadlock (can happen with QtAudio/PA bugs)
|
||||
if (!coreThread->isFinished())
|
||||
coreThread->terminate();
|
||||
delete core;
|
||||
delete camview;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user