mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Merge branch 'av_groupchats'
This commit is contained in:
commit
2c9c96e55f
23
src/core.cpp
23
src/core.cpp
|
@ -45,12 +45,16 @@ const QString Core::CONFIG_FILE_NAME = "data";
|
|||
const QString Core::TOX_EXT = ".tox";
|
||||
QList<ToxFile> Core::fileSendQueue;
|
||||
QList<ToxFile> Core::fileRecvQueue;
|
||||
QHash<int, ToxGroupCall> Core::groupCalls;
|
||||
QThread* Core::coreThread{nullptr};
|
||||
|
||||
Core::Core(Camera* cam, QThread *coreThread, QString loadPath) :
|
||||
Core::Core(Camera* cam, QThread *CoreThread, QString loadPath) :
|
||||
tox(nullptr), camera(cam), loadPath(loadPath), ready{false}
|
||||
{
|
||||
qDebug() << "Core: loading Tox from" << loadPath;
|
||||
|
||||
coreThread = CoreThread;
|
||||
|
||||
videobuf = new uint8_t[videobufsize];
|
||||
|
||||
for (int i = 0; i < ptCounter; i++)
|
||||
|
@ -95,12 +99,15 @@ Core::Core(Camera* cam, QThread *coreThread, QString loadPath) :
|
|||
}
|
||||
|
||||
QString inDevDescr = Settings::getInstance().getInDev();
|
||||
int stereoFlag = av_DefaultSettings.audio_channels==1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
|
||||
if (inDevDescr.isEmpty())
|
||||
alInDev = alcCaptureOpenDevice(nullptr,av_DefaultSettings.audio_sample_rate, AL_FORMAT_MONO16,
|
||||
(av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4) / 1000);
|
||||
alInDev = alcCaptureOpenDevice(nullptr,av_DefaultSettings.audio_sample_rate, stereoFlag,
|
||||
(av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4)
|
||||
/ 1000 * av_DefaultSettings.audio_channels);
|
||||
else
|
||||
alInDev = alcCaptureOpenDevice(inDevDescr.toStdString().c_str(),av_DefaultSettings.audio_sample_rate, AL_FORMAT_MONO16,
|
||||
(av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4) / 1000);
|
||||
alInDev = alcCaptureOpenDevice(inDevDescr.toStdString().c_str(),av_DefaultSettings.audio_sample_rate, stereoFlag,
|
||||
(av_DefaultSettings.audio_frame_duration * av_DefaultSettings.audio_sample_rate * 4)
|
||||
/ 1000 * av_DefaultSettings.audio_channels);
|
||||
if (!alInDev)
|
||||
qWarning() << "Core: Cannot open input audio device";
|
||||
}
|
||||
|
@ -1632,11 +1639,17 @@ void Core::groupInviteFriend(int friendId, int groupId)
|
|||
void Core::createGroup(uint8_t type)
|
||||
{
|
||||
if (type == TOX_GROUPCHAT_TYPE_TEXT)
|
||||
{
|
||||
emit emptyGroupCreated(tox_add_groupchat(tox));
|
||||
}
|
||||
else if (type == TOX_GROUPCHAT_TYPE_AV)
|
||||
{
|
||||
emit emptyGroupCreated(toxav_add_av_groupchat(tox, playGroupAudio, this));
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "Core::createGroup: Unknown type "<<type;
|
||||
}
|
||||
}
|
||||
|
||||
bool Core::hasFriendWithAddress(const QString &addr) const
|
||||
|
|
11
src/core.h
11
src/core.h
|
@ -117,6 +117,13 @@ public slots:
|
|||
void micMuteToggle(int callId);
|
||||
void volMuteToggle(int callId);
|
||||
|
||||
static void joinGroupCall(int groupId); ///< Starts a call in an existing AV groupchat
|
||||
static void leaveGroupCall(int groupId); ///< Will not leave the group, just stop the call
|
||||
static void disableGroupCallMic(int groupId);
|
||||
static void disableGroupCallVol(int groupId);
|
||||
static void enableGroupCallMic(int groupId);
|
||||
static void enableGroupCallVol(int groupId);
|
||||
|
||||
void setPassword(QString& password, PasswordType passtype, uint8_t* salt = nullptr);
|
||||
void clearPassword(PasswordType passtype);
|
||||
QByteArray encryptData(const QByteArray& data, PasswordType passtype);
|
||||
|
@ -235,6 +242,7 @@ private:
|
|||
|
||||
static void playGroupAudio(Tox* tox, int groupnumber, int friendgroupnumber, const int16_t* out_audio,
|
||||
unsigned out_audio_samples, uint8_t decoder_channels, unsigned audio_sample_rate, void* userdata);
|
||||
static void sendGroupCallAudio(int groupId, ToxAv* toxav);
|
||||
|
||||
static void prepareCall(int friendId, int callId, ToxAv *toxav, bool videoEnabled);
|
||||
static void cleanupCall(int callId);
|
||||
|
@ -268,6 +276,7 @@ private:
|
|||
int dhtServerId;
|
||||
static QList<ToxFile> fileSendQueue, fileRecvQueue;
|
||||
static ToxCall calls[];
|
||||
static QHash<int, ToxGroupCall> groupCalls; // Maps group IDs to ToxGroupCalls
|
||||
QMutex fileSendMutex, messageSendMutex;
|
||||
bool ready;
|
||||
|
||||
|
@ -278,6 +287,8 @@ private:
|
|||
|
||||
static ALCdevice* alOutDev, *alInDev;
|
||||
static ALCcontext* alContext;
|
||||
|
||||
static QThread *coreThread;
|
||||
public:
|
||||
static ALuint alMainSource;
|
||||
};
|
||||
|
|
108
src/coreav.cpp
108
src/coreav.cpp
|
@ -176,7 +176,6 @@ void Core::startCall(int friendId, bool video)
|
|||
emit avCallFailed(friendId);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,7 +221,7 @@ void Core::sendCallAudio(int callId, ToxAv* toxav)
|
|||
return;
|
||||
}
|
||||
|
||||
int framesize = (calls[callId].codecSettings.audio_frame_duration * calls[callId].codecSettings.audio_sample_rate) / 1000;
|
||||
int framesize = (calls[callId].codecSettings.audio_frame_duration * calls[callId].codecSettings.audio_sample_rate) / 1000 * av_DefaultSettings.audio_channels;
|
||||
uint8_t buf[framesize*2], dest[framesize*2];
|
||||
|
||||
bool frame = false;
|
||||
|
@ -578,7 +577,7 @@ void Core::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, un
|
|||
if(state != AL_PLAYING)
|
||||
{
|
||||
alSourcePlay(alSource);
|
||||
qDebug() << "Core: Starting audio source " << (int)alSource;
|
||||
//qDebug() << "Core: Starting audio source " << (int)alSource;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -587,10 +586,107 @@ VideoSource *Core::getVideoSourceFromCall(int callNumber)
|
|||
return &calls[callNumber].videoSource;
|
||||
}
|
||||
|
||||
void Core::playGroupAudio(Tox* /*tox*/, int /*groupnumber*/, int /*friendgroupnumber*/, const int16_t* out_audio,
|
||||
void Core::playGroupAudio(Tox* /*tox*/, int groupnumber, int /*friendgroupnumber*/, const int16_t* out_audio,
|
||||
unsigned out_audio_samples, uint8_t decoder_channels, unsigned audio_sample_rate, void* /*userdata*/)
|
||||
{
|
||||
/// TODO: FIXME: Don't play groupchat audio on the main source!
|
||||
/// We'll need some sort of call[] array but for groupchats, when that's done use this source
|
||||
if (!groupCalls[groupnumber].active)
|
||||
return;
|
||||
|
||||
if (!groupCalls[groupbumber].muteVol)
|
||||
return;
|
||||
|
||||
playAudioBuffer(alMainSource, out_audio, out_audio_samples, decoder_channels, audio_sample_rate);
|
||||
}
|
||||
|
||||
void Core::joinGroupCall(int groupId)
|
||||
{
|
||||
qDebug() << QString("Core: Joining group call %1").arg(groupId);
|
||||
groupCalls[groupId].groupId = groupId;
|
||||
groupCalls[groupId].muteMic = false;
|
||||
groupCalls[groupId].muteVol = false;
|
||||
// the following three lines are also now redundant from startCall, but are
|
||||
// necessary there for outbound and here for inbound
|
||||
groupCalls[groupId].codecSettings = av_DefaultSettings;
|
||||
groupCalls[groupId].codecSettings.max_video_width = TOXAV_MAX_VIDEO_WIDTH;
|
||||
groupCalls[groupId].codecSettings.max_video_height = TOXAV_MAX_VIDEO_HEIGHT;
|
||||
|
||||
// Audio
|
||||
alGenSources(1, &groupCalls[groupId].alSource);
|
||||
alcCaptureStart(alInDev);
|
||||
|
||||
// Go
|
||||
ToxAv* toxav = Core::getInstance()->toxav;
|
||||
groupCalls[groupId].sendAudioTimer = new QTimer();
|
||||
groupCalls[groupId].sendAudioTimer->moveToThread(coreThread);
|
||||
groupCalls[groupId].active = true;
|
||||
groupCalls[groupId].sendAudioTimer->setInterval(5);
|
||||
groupCalls[groupId].sendAudioTimer->setSingleShot(true);
|
||||
connect(groupCalls[groupId].sendAudioTimer, &QTimer::timeout, [=](){sendGroupCallAudio(groupId,toxav);});
|
||||
groupCalls[groupId].sendAudioTimer->start();
|
||||
}
|
||||
|
||||
void Core::leaveGroupCall(int groupId)
|
||||
{
|
||||
qDebug() << QString("Core: Leaving group call %1").arg(groupId);
|
||||
groupCalls[groupId].active = false;
|
||||
disconnect(groupCalls[groupId].sendAudioTimer,0,0,0);
|
||||
groupCalls[groupId].sendAudioTimer->stop();
|
||||
alcCaptureStop(alInDev);
|
||||
}
|
||||
|
||||
void Core::sendGroupCallAudio(int groupId, ToxAv* toxav)
|
||||
{
|
||||
if (!groupCalls[groupId].active)
|
||||
return;
|
||||
|
||||
if (groupCalls[groupId].muteMic)
|
||||
{
|
||||
groupCalls[groupId].sendAudioTimer->start();
|
||||
return;
|
||||
}
|
||||
|
||||
int framesize = (groupCalls[groupId].codecSettings.audio_frame_duration * groupCalls[groupId].codecSettings.audio_sample_rate) / 1000 * av_DefaultSettings.audio_channels;
|
||||
uint8_t buf[framesize*2];
|
||||
|
||||
bool frame = false;
|
||||
ALint samples;
|
||||
alcGetIntegerv(alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
|
||||
if(samples >= framesize)
|
||||
{
|
||||
alcCaptureSamples(alInDev, buf, framesize);
|
||||
frame = 1;
|
||||
}
|
||||
|
||||
if(frame)
|
||||
{
|
||||
int r;
|
||||
if((r = toxav_group_send_audio(toxav_get_tox(toxav), groupId, (int16_t*)buf,
|
||||
framesize, av_DefaultSettings.audio_channels, av_DefaultSettings.audio_sample_rate)) < 0)
|
||||
{
|
||||
qDebug() << "Core: toxav_group_send_audio error";
|
||||
groupCalls[groupId].sendAudioTimer->start();
|
||||
return;
|
||||
}
|
||||
}
|
||||
groupCalls[groupId].sendAudioTimer->start();
|
||||
}
|
||||
|
||||
void Core::disableGroupCallMic(int groupId)
|
||||
{
|
||||
groupCalls[groupId].muteMic = true;
|
||||
}
|
||||
|
||||
void Core::disableGroupCallVol(int groupId)
|
||||
{
|
||||
groupCalls[groupId].muteVol = true;
|
||||
}
|
||||
|
||||
void Core::enableGroupCallMic(int groupId)
|
||||
{
|
||||
groupCalls[groupId].muteMic = false;
|
||||
}
|
||||
|
||||
void Core::enableGroupCallVol(int groupId)
|
||||
{
|
||||
groupCalls[groupId].muteVol = false;
|
||||
}
|
||||
|
|
12
src/coreav.h
12
src/coreav.h
|
@ -16,7 +16,6 @@ class QTimer;
|
|||
|
||||
struct ToxCall
|
||||
{
|
||||
public:
|
||||
ToxAvCSettings codecSettings;
|
||||
QTimer *sendAudioTimer, *sendVideoTimer;
|
||||
int callId;
|
||||
|
@ -29,4 +28,15 @@ public:
|
|||
NetVideoSource videoSource;
|
||||
};
|
||||
|
||||
struct ToxGroupCall
|
||||
{
|
||||
ToxAvCSettings codecSettings;
|
||||
QTimer *sendAudioTimer;
|
||||
int groupId;
|
||||
bool active;
|
||||
bool muteMic;
|
||||
bool muteVol;
|
||||
ALuint alSource;
|
||||
};
|
||||
|
||||
#endif // COREAV_H
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
|
||||
Group::Group(int GroupId, QString Name)
|
||||
: groupId(GroupId), nPeers{0}
|
||||
Group::Group(int GroupId, QString Name, bool IsAvGroupchat)
|
||||
: groupId(GroupId), nPeers{0}, avGroupchat{IsAvGroupchat}
|
||||
{
|
||||
widget = new GroupWidget(groupId, Name);
|
||||
chatForm = new GroupChatForm(this);
|
||||
|
|
|
@ -30,7 +30,7 @@ class Group : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Group(int GroupId, QString Name);
|
||||
Group(int GroupId, QString Name, bool IsAvGroupchat);
|
||||
~Group();
|
||||
void addPeer(int peerId, QString name);
|
||||
void removePeer(int peerId);
|
||||
|
@ -43,6 +43,7 @@ public:
|
|||
GroupWidget* widget;
|
||||
GroupChatForm* chatForm;
|
||||
int hasNewMessages, userWasMentioned;
|
||||
bool avGroupchat;
|
||||
};
|
||||
|
||||
#endif // GROUP_H
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
|
||||
QList<Group*> GroupList::groupList;
|
||||
|
||||
Group* GroupList::addGroup(int groupId, const QString& name)
|
||||
Group* GroupList::addGroup(int groupId, const QString& name, bool isAvGroupchat)
|
||||
{
|
||||
Group* newGroup = new Group(groupId, name);
|
||||
Group* newGroup = new Group(groupId, name, isAvGroupchat);
|
||||
groupList.append(newGroup);
|
||||
return newGroup;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class GroupList
|
|||
{
|
||||
public:
|
||||
GroupList();
|
||||
static Group* addGroup(int groupId, const QString& name);
|
||||
static Group* addGroup(int groupId, const QString& name, bool isAvGroupchat);
|
||||
static Group* findGroup(int groupId);
|
||||
static void removeGroup(int groupId, bool fake = false);
|
||||
|
||||
|
|
|
@ -43,8 +43,6 @@
|
|||
|
||||
ChatForm::ChatForm(Friend* chatFriend)
|
||||
: f(chatFriend)
|
||||
, audioInputFlag(false)
|
||||
, audioOutputFlag(false)
|
||||
, callId(0)
|
||||
{
|
||||
nameLabel->setText(f->getDisplayedName());
|
||||
|
|
|
@ -95,8 +95,6 @@ private:
|
|||
Friend* f;
|
||||
CroppingLabel *statusMessageLabel;
|
||||
NetCamView* netcam;
|
||||
bool audioInputFlag;
|
||||
bool audioOutputFlag;
|
||||
int callId;
|
||||
QLabel *callDuration;
|
||||
QTimer *timer;
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
GenericChatForm::GenericChatForm(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
earliestMessage(nullptr)
|
||||
, audioInputFlag(false)
|
||||
, audioOutputFlag(false)
|
||||
{
|
||||
curRow = 0;
|
||||
|
||||
|
|
|
@ -91,6 +91,8 @@ protected:
|
|||
QPushButton *sendButton;
|
||||
ChatAreaWidget *chatWidget;
|
||||
QDateTime *earliestMessage;
|
||||
bool audioInputFlag;
|
||||
bool audioOutputFlag;
|
||||
};
|
||||
|
||||
#endif // GENERICCHATFORM_H
|
||||
|
|
|
@ -30,17 +30,25 @@
|
|||
#include "src/misc/flowlayout.h"
|
||||
|
||||
GroupChatForm::GroupChatForm(Group* chatGroup)
|
||||
: group(chatGroup)
|
||||
: group(chatGroup), inCall{false}
|
||||
{
|
||||
nusersLabel = new QLabel();
|
||||
|
||||
tabber = new TabCompleter(msgEdit, group);
|
||||
|
||||
fileButton->setEnabled(false);
|
||||
callButton->setVisible(false);
|
||||
if (group->avGroupchat)
|
||||
{
|
||||
videoButton->setEnabled(false);
|
||||
videoButton->setObjectName("grey");
|
||||
}
|
||||
else
|
||||
{
|
||||
videoButton->setVisible(false);
|
||||
callButton->setVisible(false);
|
||||
volButton->setVisible(false);
|
||||
micButton->setVisible(false);
|
||||
}
|
||||
|
||||
nameLabel->setText(group->widget->getName());
|
||||
|
||||
|
@ -68,6 +76,9 @@ GroupChatForm::GroupChatForm(Group* chatGroup)
|
|||
connect(msgEdit, SIGNAL(enterPressed()), this, SLOT(onSendTriggered()));
|
||||
connect(msgEdit, &ChatTextEdit::tabPressed, tabber, &TabCompleter::complete);
|
||||
connect(msgEdit, &ChatTextEdit::keyPressed, tabber, &TabCompleter::reset);
|
||||
connect(callButton, &QPushButton::clicked, this, &GroupChatForm::onCallClicked);
|
||||
connect(micButton, SIGNAL(clicked()), this, SLOT(onMicMuteToggle()));
|
||||
connect(volButton, SIGNAL(clicked()), this, SLOT(onVolMuteToggle()));
|
||||
|
||||
setAcceptDrops(true);
|
||||
}
|
||||
|
@ -129,3 +140,66 @@ void GroupChatForm::dropEvent(QDropEvent *ev)
|
|||
}
|
||||
}
|
||||
|
||||
void GroupChatForm::onMicMuteToggle()
|
||||
{
|
||||
if (audioInputFlag == true)
|
||||
{
|
||||
if (micButton->objectName() == "red")
|
||||
{
|
||||
Core::getInstance()->enableGroupCallMic(group->groupId);
|
||||
micButton->setObjectName("green");
|
||||
}
|
||||
else
|
||||
{
|
||||
Core::getInstance()->disableGroupCallMic(group->groupId);
|
||||
micButton->setObjectName("red");
|
||||
}
|
||||
|
||||
Style::repolish(micButton);
|
||||
}
|
||||
}
|
||||
|
||||
void GroupChatForm::onVolMuteToggle()
|
||||
{
|
||||
if (audioOutputFlag == true)
|
||||
{
|
||||
if (volButton->objectName() == "red")
|
||||
{
|
||||
Core::getInstance()->enableGroupCallVol(group->groupId);
|
||||
volButton->setObjectName("green");
|
||||
}
|
||||
else
|
||||
{
|
||||
Core::getInstance()->disableGroupCallVol(group->groupId);
|
||||
volButton->setObjectName("red");
|
||||
}
|
||||
|
||||
Style::repolish(volButton);
|
||||
}
|
||||
}
|
||||
|
||||
void GroupChatForm::onCallClicked()
|
||||
{
|
||||
if (!inCall)
|
||||
{
|
||||
Core::getInstance()->joinGroupCall(group->groupId);
|
||||
audioInputFlag = true;
|
||||
audioOutputFlag = true;
|
||||
callButton->setObjectName("red");
|
||||
callButton->style()->polish(callButton);
|
||||
inCall = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Core::getInstance()->leaveGroupCall(group->groupId);
|
||||
audioInputFlag = false;
|
||||
audioOutputFlag = false;
|
||||
micButton->setObjectName("green");
|
||||
micButton->style()->polish(micButton);
|
||||
volButton->setObjectName("green");
|
||||
volButton->style()->polish(volButton);
|
||||
callButton->setObjectName("green");
|
||||
callButton->style()->polish(callButton);
|
||||
inCall = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,9 @@ public:
|
|||
|
||||
private slots:
|
||||
void onSendTriggered();
|
||||
void onMicMuteToggle();
|
||||
void onVolMuteToggle();
|
||||
void onCallClicked();
|
||||
|
||||
protected:
|
||||
// drag & drop
|
||||
|
@ -45,6 +48,7 @@ private:
|
|||
FlowLayout* namesListLayout;
|
||||
QLabel *nusersLabel;
|
||||
TabCompleter* tabber;
|
||||
bool inCall;
|
||||
};
|
||||
|
||||
#endif // GROUPCHATFORM_H
|
||||
|
|
|
@ -985,7 +985,7 @@ Group *Widget::createGroup(int groupId)
|
|||
}
|
||||
|
||||
QString groupName = QString("Groupchat #%1").arg(groupId);
|
||||
Group* newgroup = GroupList::addGroup(groupId, groupName);
|
||||
Group* newgroup = GroupList::addGroup(groupId, groupName, true);
|
||||
QLayout* layout = contactListWidget->getGroupLayout();
|
||||
layout->addWidget(newgroup->widget);
|
||||
newgroup->widget->updateStatusLight();
|
||||
|
|
Loading…
Reference in New Issue
Block a user