Browse Source

Merge 4cb64e6fe2 into 6c6620ffc1

pull/6235/merge
sudden6 4 years ago committed by GitHub
parent
commit
34a702c348
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 256
      src/core/coreav.cpp
  2. 37
      src/core/coreav.h
  3. 15
      src/core/toxcall.cpp
  4. 13
      src/core/toxcall.h
  5. 82
      src/widget/form/chatform.cpp
  6. 4
      src/widget/form/chatform.h
  7. 57
      src/widget/form/groupchatform.cpp
  8. 4
      src/widget/form/groupchatform.h
  9. 14
      src/widget/widget.cpp
  10. 1
      src/widget/widget.h

256
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()
@ -195,43 +196,6 @@ void CoreAV::process() @@ -195,43 +196,6 @@ void CoreAV::process()
iterateTimer->start(toxav_iteration_interval(toxav.get()));
}
/**
* @brief Checks the call status for a Tox friend.
* @param f the friend to check
* @return true, if call is started for the friend, false otherwise
*/
bool CoreAV::isCallStarted(const Friend* f) const
{
QReadLocker locker{&callsLock};
return f && (calls.find(f->getId()) != calls.end());
}
/**
* @brief Checks the call status for a Tox group.
* @param g the group to check
* @return true, if call is started for the group, false otherwise
*/
bool CoreAV::isCallStarted(const Group* g) const
{
QReadLocker locker{&callsLock};
return g && (groupCalls.find(g->getId()) != groupCalls.end());
}
/**
* @brief Checks the call status for a Tox friend.
* @param f the friend to check
* @return true, if call is active for the friend, false otherwise
*/
bool CoreAV::isCallActive(const Friend* f) const
{
QReadLocker locker{&callsLock};
auto it = calls.find(f->getId());
if (it == calls.end()) {
return false;
}
return isCallStarted(f) && it->second->isActive();
}
/**
* @brief Checks the call status for a Tox group.
* @param g the group to check
@ -244,14 +208,7 @@ bool CoreAV::isCallActive(const Group* g) const @@ -244,14 +208,7 @@ bool CoreAV::isCallActive(const Group* g) const
if (it == groupCalls.end()) {
return false;
}
return isCallStarted(g) && it->second->isActive();
}
bool CoreAV::isCallVideoEnabled(const Friend* f) const
{
QReadLocker locker{&callsLock};
auto it = calls.find(f->getId());
return isCallStarted(f) && it->second->getVideoEnabled();
return it->second->isActive();
}
bool CoreAV::answerCall(uint32_t friendNum, bool video)
@ -279,7 +236,7 @@ bool CoreAV::answerCall(uint32_t friendNum, bool video) @@ -279,7 +236,7 @@ bool CoreAV::answerCall(uint32_t friendNum, bool video)
}
}
bool CoreAV::startCall(uint32_t friendNum, bool video)
CoreAV::ToxFriendCallPtr CoreAV::startCall(uint32_t friendNum, bool video)
{
QWriteLocker locker{&callsLock};
QMutexLocker coreLocker{&coreLock};
@ -288,7 +245,7 @@ bool CoreAV::startCall(uint32_t friendNum, bool video) @@ -288,7 +245,7 @@ bool CoreAV::startCall(uint32_t friendNum, bool video)
auto it = calls.find(friendNum);
if (it != calls.end()) {
qWarning() << QString("Can't start call with %1, we're already in this call!").arg(friendNum);
return false;
return {};
}
uint32_t videoBitrate = video ? VIDEO_DEFAULT_BITRATE : 0;
@ -296,7 +253,7 @@ bool CoreAV::startCall(uint32_t friendNum, bool video) @@ -296,7 +253,7 @@ bool CoreAV::startCall(uint32_t friendNum, bool video)
toxav_call(toxav.get(), friendNum, audioSettings.getAudioBitrate(), videoBitrate,
&err);
if (!PARSE_ERR(err)) {
return false;
return {};
}
// Audio backend must be set before making a call
@ -306,8 +263,8 @@ bool CoreAV::startCall(uint32_t friendNum, bool video) @@ -306,8 +263,8 @@ bool 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, std::move(call));
return true;
calls.emplace(friendNum, call.get());
return call;
}
bool CoreAV::cancelCall(uint32_t friendNum)
@ -315,6 +272,11 @@ bool CoreAV::cancelCall(uint32_t friendNum) @@ -315,6 +272,11 @@ bool CoreAV::cancelCall(uint32_t friendNum)
QWriteLocker locker{&callsLock};
QMutexLocker coreLocker{&coreLock};
auto it = calls.find(friendNum);
if (it == calls.end()) {
return false;
}
qDebug() << QString("Cancelling call with %1").arg(friendNum);
Toxav_Err_Call_Control err;
toxav_call_control(toxav.get(), friendNum, TOXAV_CALL_CONTROL_CANCEL, &err);
@ -329,17 +291,6 @@ bool CoreAV::cancelCall(uint32_t friendNum) @@ -329,17 +291,6 @@ bool CoreAV::cancelCall(uint32_t friendNum)
return true;
}
void CoreAV::timeoutCall(uint32_t friendNum)
{
QWriteLocker locker{&callsLock};
if (!cancelCall(friendNum)) {
qWarning() << QString("Failed to timeout call with %1").arg(friendNum);
return;
}
qDebug() << "Call with friend" << friendNum << "timed out";
}
/**
* @brief Send audio frame to a friend
* @param callId Id of friend in call list.
@ -441,36 +392,6 @@ void CoreAV::sendCallVideo(uint32_t callId, std::shared_ptr<VideoFrame> vframe) @@ -441,36 +392,6 @@ void CoreAV::sendCallVideo(uint32_t callId, std::shared_ptr<VideoFrame> vframe)
}
}
/**
* @brief Toggles the mute state of the call's input (microphone).
* @param f The friend assigned to the call
*/
void CoreAV::toggleMuteCallInput(const Friend* f)
{
QWriteLocker locker{&callsLock};
auto it = calls.find(f->getId());
if (f && (it != calls.end())) {
ToxCall& call = *it->second;
call.setMuteMic(!call.getMuteMic());
}
}
/**
* @brief Toggles the mute state of the call's output (speaker).
* @param f The friend assigned to the call
*/
void CoreAV::toggleMuteCallOutput(const Friend* f)
{
QWriteLocker locker{&callsLock};
auto it = calls.find(f->getId());
if (f && (it != calls.end())) {
ToxCall& call = *it->second;
call.setMuteVol(!call.getMuteVol());
}
}
/**
* @brief Called from Tox API when group call receives audio data.
*
@ -513,7 +434,7 @@ void CoreAV::groupCallCallback(void* tox, uint32_t group, uint32_t peer, const i @@ -513,7 +434,7 @@ void CoreAV::groupCallCallback(void* tox, uint32_t group, uint32_t peer, const i
return;
}
ToxGroupCall& call = *it->second;
auto& call = *it->second;
if (call.getMuteVol() || !call.isActive()) {
return;
@ -522,46 +443,12 @@ void CoreAV::groupCallCallback(void* tox, uint32_t group, uint32_t peer, const i @@ -522,46 +443,12 @@ void CoreAV::groupCallCallback(void* tox, uint32_t group, uint32_t peer, const i
call.playAudioBuffer(peerPk, data, samples, channels, sample_rate);
}
/**
* @brief Called from core to make sure the source for that peer is invalidated when they leave.
* @param group Group Index
* @param peer Peer Index
*/
void CoreAV::invalidateGroupCallPeerSource(const Group& group, ToxPk peerPk)
{
QWriteLocker locker{&callsLock};
auto it = groupCalls.find(group.getId());
if (it == groupCalls.end()) {
return;
}
it->second->removePeer(peerPk);
}
/**
* @brief Get a call's video source.
* @param friendNum Id of friend in call list.
* @return Video surface to show
*/
VideoSource* CoreAV::getVideoSourceFromCall(int friendNum) const
{
QReadLocker locker{&callsLock};
auto it = calls.find(friendNum);
if (it == calls.end()) {
qWarning() << "CoreAV::getVideoSourceFromCall: No such call, possibly cancelled";
return nullptr;
}
return it->second->getVideoSource();
}
/**
* @brief Starts a call in an existing AV groupchat.
* @note Call from the GUI thread.
* @param groupId Id of group to join
*/
void CoreAV::joinGroupCall(const Group& group)
CoreAV::ToxGroupCallPtr CoreAV::joinGroupCall(const Group& group)
{
QWriteLocker locker{&callsLock};
@ -572,14 +459,15 @@ void CoreAV::joinGroupCall(const Group& group) @@ -572,14 +459,15 @@ void CoreAV::joinGroupCall(const Group& group)
ToxGroupCallPtr groupcall = ToxGroupCallPtr(new ToxGroupCall{group, *this, *audio});
// Call Objects must be owned by CoreAV or there will be locking problems with Audio
groupcall->moveToThread(thread());
assert(groupcall != nullptr);
auto ret = groupCalls.emplace(group.getId(), std::move(groupcall));
groupcall->moveToThread(this->thread());
auto ret = groupCalls.emplace(group.getId(), groupcall.get());
if (ret.second == false) {
qWarning() << "This group call already exists, not joining!";
return;
return {};
}
ret.first->second->setActive(true);
groupcall->setActive(true);
return groupcall;
}
/**
@ -601,7 +489,7 @@ bool CoreAV::sendGroupCallAudio(int groupNum, const int16_t* pcm, size_t samples @@ -601,7 +489,7 @@ bool CoreAV::sendGroupCallAudio(int groupNum, const int16_t* pcm, size_t samples
{
QReadLocker locker{&callsLock};
std::map<int, ToxGroupCallPtr>::const_iterator it = groupCalls.find(groupNum);
auto it = groupCalls.find(groupNum);
if (it == groupCalls.end()) {
return false;
}
@ -616,106 +504,6 @@ bool CoreAV::sendGroupCallAudio(int groupNum, const int16_t* pcm, size_t samples @@ -616,106 +504,6 @@ bool CoreAV::sendGroupCallAudio(int groupNum, const int16_t* pcm, size_t samples
return true;
}
/**
* @brief Mutes or unmutes the group call's input (microphone).
* @param g The group
* @param mute True to mute, false to unmute
*/
void CoreAV::muteCallInput(const Group* g, bool mute)
{
QWriteLocker locker{&callsLock};
auto it = groupCalls.find(g->getId());
if (g && (it != groupCalls.end())) {
it->second->setMuteMic(mute);
}
}
/**
* @brief Mutes or unmutes the group call's output (speaker).
* @param g The group
* @param mute True to mute, false to unmute
*/
void CoreAV::muteCallOutput(const Group* g, bool mute)
{
QWriteLocker locker{&callsLock};
auto it = groupCalls.find(g->getId());
if (g && (it != groupCalls.end())) {
it->second->setMuteVol(mute);
}
}
/**
* @brief Returns the group calls input (microphone) state.
* @param groupId The group id to check
* @return true when muted, false otherwise
*/
bool CoreAV::isGroupCallInputMuted(const Group* g) const
{
QReadLocker locker{&callsLock};
if (!g) {
return false;
}
const uint32_t groupId = g->getId();
auto it = groupCalls.find(groupId);
return (it != groupCalls.end()) && it->second->getMuteMic();
}
/**
* @brief Returns the group calls output (speaker) state.
* @param groupId The group id to check
* @return true when muted, false otherwise
*/
bool CoreAV::isGroupCallOutputMuted(const Group* g) const
{
QReadLocker locker{&callsLock};
if (!g) {
return false;
}
const uint32_t groupId = g->getId();
auto it = groupCalls.find(groupId);
return (it != groupCalls.end()) && it->second->getMuteVol();
}
/**
* @brief Returns the calls input (microphone) mute state.
* @param f The friend to check
* @return true when muted, false otherwise
*/
bool CoreAV::isCallInputMuted(const Friend* f) const
{
QReadLocker locker{&callsLock};
if (!f) {
return false;
}
const uint32_t friendId = f->getId();
auto it = calls.find(friendId);
return (it != calls.end()) && it->second->getMuteMic();
}
/**
* @brief Returns the calls output (speaker) mute state.
* @param friendId The friend to check
* @return true when muted, false otherwise
*/
bool CoreAV::isCallOutputMuted(const Friend* f) const
{
QReadLocker locker{&callsLock};
if (!f) {
return false;
}
const uint32_t friendId = f->getId();
auto it = calls.find(friendId);
return (it != calls.end()) && it->second->getMuteVol();
}
/**
* @brief Signal to all peers that we're not sending video anymore.
* @note The next frame sent cancels this.
@ -751,7 +539,7 @@ void CoreAV::callCallback(ToxAV* toxav, uint32_t friendNum, bool audio, bool vid @@ -751,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;
@ -772,7 +560,7 @@ void CoreAV::callCallback(ToxAV* toxav, uint32_t friendNum, bool audio, bool vid @@ -772,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)

37
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,12 +45,18 @@ class VideoFrame; @@ -44,12 +45,18 @@ 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::unique_ptr<ToxGroupCall>;
static CoreAVPtr makeCoreAV(Tox* core, CompatibleRecursiveMutex& toxCoreLock,
IAudioSettings& audioSettings, IGroupSettings& groupSettings,
CameraSource& cameraSource);
@ -59,45 +66,30 @@ public: @@ -59,45 +66,30 @@ public:
~CoreAV();
bool isCallStarted(const Friend* f) const;
bool isCallStarted(const Group* g) const;
bool isCallActive(const Friend* f) const;
bool isCallActive(const Group* g) const;
bool isCallVideoEnabled(const Friend* f) const;
bool sendCallAudio(uint32_t callId, const int16_t* pcm, size_t samples, uint8_t chans,
uint32_t rate) const;
void sendCallVideo(uint32_t callId, std::shared_ptr<VideoFrame> frame);
bool sendGroupCallAudio(int groupNum, const int16_t* pcm, size_t samples, uint8_t chans,
uint32_t rate) const;
VideoSource* getVideoSourceFromCall(int friendNum) const;
void sendNoVideo();
void joinGroupCall(const Group& group);
ToxGroupCallPtr joinGroupCall(const Group& group);
void leaveGroupCall(int groupNum);
void muteCallInput(const Group* g, bool mute);
void muteCallOutput(const Group* g, bool mute);
bool isGroupCallInputMuted(const Group* g) const;
bool isGroupCallOutputMuted(const Group* g) const;
bool isCallInputMuted(const Friend* f) const;
bool isCallOutputMuted(const Friend* f) const;
void toggleMuteCallInput(const Friend* f);
void toggleMuteCallOutput(const Friend* f);
static void groupCallCallback(void* tox, uint32_t group, uint32_t peer, const int16_t* data,
unsigned samples, uint8_t channels, uint32_t sample_rate,
void* core);
void invalidateGroupCallPeerSource(const Group& group, ToxPk peerPk);
public slots:
bool startCall(uint32_t friendNum, bool video);
ToxFriendCallPtr startCall(uint32_t friendNum, bool video);
bool answerCall(uint32_t friendNum, bool video);
bool cancelCall(uint32_t friendNum);
void timeoutCall(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);
@ -139,20 +131,17 @@ private: @@ -139,20 +131,17 @@ private:
std::unique_ptr<ToxAV, ToxAVDeleter> toxav;
std::unique_ptr<QThread> coreavThread;
QTimer* iterateTimer = nullptr;
using ToxFriendCallPtr = std::unique_ptr<ToxFriendCall>;
/**
* @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;
using ToxGroupCallPtr = std::unique_ptr<ToxGroupCall>;
/**
* @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};

15
src/core/toxcall.cpp

@ -49,7 +49,7 @@ @@ -49,7 +49,7 @@
*/
ToxCall::ToxCall(bool VideoEnabled_, CoreAV& av_, IAudioControl& audio_)
: av{&av_}
: av{av_}
, audio(audio_)
, videoEnabled{VideoEnabled_}
, audioSource(audio_.makeSource())
@ -126,7 +126,7 @@ ToxFriendCall::ToxFriendCall(uint32_t friendNum, bool VideoEnabled, CoreAV& av_, @@ -126,7 +126,7 @@ ToxFriendCall::ToxFriendCall(uint32_t friendNum, bool VideoEnabled, CoreAV& av_,
{
connect(audioSource.get(), &IAudioSource::frameAvailable, this,
[this](const int16_t* pcm, size_t samples, uint8_t chans, uint32_t rate) {
av->sendCallAudio(friendId, pcm, samples, chans, rate);
av.sendCallAudio(friendId, pcm, samples, chans, rate);
});
connect(audioSource.get(), &IAudioSource::invalidated, this, &ToxFriendCall::onAudioSourceInvalidated);
@ -155,9 +155,7 @@ ToxFriendCall::ToxFriendCall(uint32_t friendNum, bool VideoEnabled, CoreAV& av_, @@ -155,9 +155,7 @@ ToxFriendCall::ToxFriendCall(uint32_t friendNum, bool VideoEnabled, CoreAV& av_,
ToxFriendCall::~ToxFriendCall()
{
if (videoEnabled) {
cameraSource.unsubscribe();
}
av.cancelCall(friendId);
QObject::disconnect(audioSinkInvalid);
}
@ -166,7 +164,7 @@ void ToxFriendCall::onAudioSourceInvalidated() @@ -166,7 +164,7 @@ void ToxFriendCall::onAudioSourceInvalidated()
auto newSrc = audio.makeSource();
connect(newSrc.get(), &IAudioSource::frameAvailable, this,
[this](const int16_t* pcm, size_t samples, uint8_t chans, uint32_t rate) {
av->sendCallAudio(friendId, pcm, samples, chans, rate);
av.sendCallAudio(friendId, pcm, samples, chans, rate);
});
audioSource = std::move(newSrc);
@ -213,7 +211,7 @@ ToxGroupCall::ToxGroupCall(const Group& group_, CoreAV& av_, IAudioControl& audi @@ -213,7 +211,7 @@ ToxGroupCall::ToxGroupCall(const Group& group_, CoreAV& av_, IAudioControl& audi
return;
}
av->sendGroupCallAudio(group.getId(), pcm, samples, chans, rate);
av.sendGroupCallAudio(group.getId(), pcm, samples, chans, rate);
});
connect(audioSource.get(), &IAudioSource::invalidated, this, &ToxGroupCall::onAudioSourceInvalidated);
@ -221,6 +219,7 @@ ToxGroupCall::ToxGroupCall(const Group& group_, CoreAV& av_, IAudioControl& audi @@ -221,6 +219,7 @@ ToxGroupCall::ToxGroupCall(const Group& group_, CoreAV& av_, IAudioControl& audi
ToxGroupCall::~ToxGroupCall()
{
av.leaveGroupCall(group.getId());
// disconnect all Qt connections
clearPeers();
}
@ -234,7 +233,7 @@ void ToxGroupCall::onAudioSourceInvalidated() @@ -234,7 +233,7 @@ void ToxGroupCall::onAudioSourceInvalidated()
return;
}
av->sendGroupCallAudio(group.getId(), pcm, samples, chans, rate);
av.sendGroupCallAudio(group.getId(), pcm, samples, chans, rate);
});
audioSource = std::move(newSrc);

13
src/core/toxcall.h

@ -29,6 +29,7 @@ @@ -29,6 +29,7 @@
#include <QMetaObject>
#include <QtGlobal>
#include <atomic>
#include <cstdint>
#include <memory>
@ -73,17 +74,17 @@ public: @@ -73,17 +74,17 @@ public:
CoreVideoSource* getVideoSource() const;
protected:
bool active{false};
CoreAV* av{nullptr};
std::atomic<bool> active{false};
CoreAV& av;
// audio
IAudioControl& audio;
bool muteMic{false};
bool muteVol{false};
std::atomic<bool> muteMic{false};
std::atomic<bool> muteVol{false};
// video
CoreVideoSource* videoSource{nullptr};
QMetaObject::Connection videoInConn;
bool videoEnabled{false};
bool nullVideoBitrate{false};
std::atomic<bool> videoEnabled{false};
std::atomic<bool> nullVideoBitrate{false};
std::unique_ptr<IAudioSource> audioSource;
};

82
src/widget/form/chatform.cpp

@ -34,6 +34,7 @@ @@ -34,6 +34,7 @@
#include "src/persistence/profile.h"
#include "src/persistence/settings.h"
#include "src/video/netcamview.h"
#include "src/video/corevideosource.h"
#include "src/widget/chatformheader.h"
#include "src/widget/contentdialogmanager.h"
#include "src/widget/form/loadhistorydialog.h"
@ -313,12 +314,16 @@ void ChatForm::onAttachClicked() @@ -313,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;
@ -329,10 +334,8 @@ void ChatForm::onAvInvite(uint32_t friendId, bool video) @@ -329,10 +334,8 @@ void ChatForm::onAvInvite(uint32_t friendId, bool video)
auto testedFlag = video ? Settings::AutoAcceptCall::Video : Settings::AutoAcceptCall::Audio;
// AutoAcceptCall is set for this friend
if (settings.getAutoAcceptCall(f->getPublicKey()).testFlag(testedFlag)) {
qDebug() << "automatic call answer";
CoreAV* coreav = core.getAv();
QMetaObject::invokeMethod(coreav, "answerCall", Qt::QueuedConnection,
Q_ARG(uint32_t, friendId), Q_ARG(bool, video));
onAnswerCallTriggered(video);
// CoreAV doesn't send a signal when we answer the call
onAvStart(friendId, video);
} else {
headWidget->createCallConfirm(video);
@ -365,6 +368,7 @@ void ChatForm::onAvEnd(uint32_t friendId, bool error) @@ -365,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()) {
@ -395,20 +399,29 @@ void ChatForm::onAnswerCallTriggered(bool video) @@ -395,20 +399,29 @@ void ChatForm::onAnswerCallTriggered(bool video)
emit acceptCall(friendId);
updateCallButtons();
if (!call) {
qWarning() << "Trying to answer call without receiving an invite";
}
CoreAV* av = core.getAv();
if (!av->answerCall(friendId, video)) {
bool answered = av->answerCall(friendId, video);
if (!answered) {
qDebug() << "Failed to answer call";
call.reset();
updateCallButtons();
stopCounter();
hideNetcam();
return;
}
onAvStart(friendId, av->isCallVideoEnabled(f));
// CoreAV doesn't send the avStart() signal when we answer
onAvStart(friendId, call->getVideoEnabled());
}
void ChatForm::onRejectCallTriggered()
{
headWidget->removeCallConfirm();
call.reset();
emit rejectCall(f->getId());
}
@ -416,10 +429,16 @@ void ChatForm::onCallTriggered() @@ -416,10 +429,16 @@ void ChatForm::onCallTriggered()
{
CoreAV* av = core.getAv();
uint32_t friendId = f->getId();
if (av->isCallStarted(f)) {
av->cancelCall(friendId);
} else if (av->startCall(friendId, false)) {
showOutgoingCall(false);
if (call) {
call.reset();
} else {
call = av->startCall(friendId, false);
if (call) {
showOutgoingCall(false);
} else {
qDebug() << "Failed to start Audio call";
}
}
}
@ -427,21 +446,23 @@ void ChatForm::onVideoCallTriggered() @@ -427,21 +446,23 @@ void ChatForm::onVideoCallTriggered()
{
CoreAV* av = core.getAv();
uint32_t friendId = f->getId();
if (av->isCallStarted(f)) {
// TODO: We want to activate video on the active call.
if (av->isCallVideoEnabled(f)) {
av->cancelCall(friendId);
if (call) {
call.reset();
} else {
call = av->startCall(friendId, true);
if (call) {
showOutgoingCall(true);
} else {
qDebug() << "Failed to start Video call";
}
} else if (av->startCall(friendId, true)) {
showOutgoingCall(true);
}
}
void ChatForm::updateCallButtons()
{
CoreAV* av = core.getAv();
const bool audio = av->isCallActive(f);
const bool video = av->isCallVideoEnabled(f);
const bool audio = call ? call->isActive() : false;
const bool video = call ? call->getVideoEnabled() : false;
const bool online = Status::isOnline(f->getStatus());
headWidget->updateCallButtons(online, audio, video);
updateMuteMicButton();
@ -450,15 +471,14 @@ void ChatForm::updateCallButtons() @@ -450,15 +471,14 @@ void ChatForm::updateCallButtons()
void ChatForm::onMicMuteToggle()
{
CoreAV* av = core.getAv();
av->toggleMuteCallInput(f);
// Technically this is not atomic, but the probability of hitting the non-atomic case is negible
call->setMuteMic(!call->getMuteMic());
updateMuteMicButton();
}
void ChatForm::onVolMuteToggle()
{
CoreAV* av = core.getAv();
av->toggleMuteCallOutput(f);
call->setMuteVol(!call->getMuteVol());
updateMuteVolButton();
}
@ -515,11 +535,9 @@ void ChatForm::onAvatarChanged(const ToxPk& friendPk, const QPixmap& pic) @@ -515,11 +535,9 @@ void ChatForm::onAvatarChanged(const ToxPk& friendPk, const QPixmap& pic)
std::unique_ptr<NetCamView> ChatForm::createNetcam()
{
qDebug() << "creating netcam";
uint32_t friendId = f->getId();
std::unique_ptr<NetCamView> view = std::unique_ptr<NetCamView>(
new NetCamView(f->getPublicKey(), cameraSource, settings, style, this));
CoreAV* av = core.getAv();
VideoSource* source = av->getVideoSourceFromCall(friendId);
VideoSource* source = call->getVideoSource();
view->show(source, f->getDisplayedName());
connect(view.get(), &NetCamView::videoCallEnd, this, &ChatForm::onVideoCallTriggered);
connect(view.get(), &NetCamView::volMuteToggle, this, &ChatForm::onVolMuteToggle);
@ -656,9 +674,8 @@ void ChatForm::onCopyStatusMessage() @@ -656,9 +674,8 @@ void ChatForm::onCopyStatusMessage()
void ChatForm::updateMuteMicButton()
{
const CoreAV* av = core.getAv();
bool active = av->isCallActive(f);
bool inputMuted = av->isCallInputMuted(f);
const bool active = call ? call->isActive() : false;
const bool inputMuted = call ? call->getMuteMic() : false;
headWidget->updateMuteMicButton(active, inputMuted);
if (netcam) {
netcam->updateMuteMicButton(inputMuted);
@ -667,9 +684,8 @@ void ChatForm::updateMuteMicButton() @@ -667,9 +684,8 @@ void ChatForm::updateMuteMicButton()
void ChatForm::updateMuteVolButton()
{
const CoreAV* av = core.getAv();
bool active = av->isCallActive(f);
bool outputMuted = av->isCallOutputMuted(f);
const bool active = call ? call->isActive() : false;
const bool outputMuted = call ? call->getMuteVol() : false;
headWidget->updateMuteVolButton(active, outputMuted);
if (netcam) {
netcam->updateMuteVolButton(outputMuted);

4
src/widget/form/chatform.h

@ -26,6 +26,7 @@ @@ -26,6 +26,7 @@
#include "genericchatform.h"
#include "src/core/core.h"
#include "src/core/coreav.h"
#include "src/model/ichatlog.h"
#include "src/model/imessagedispatcher.h"
#include "src/model/status.h"
@ -78,7 +79,7 @@ signals: @@ -78,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);
@ -152,4 +153,5 @@ private: @@ -152,4 +153,5 @@ private:
Settings& settings;
Style& style;
ContentDialogManager& contentDialogManager;
CoreAV::ToxFriendCallPtr call;
};

57
src/widget/form/groupchatform.cpp

@ -39,6 +39,7 @@ @@ -39,6 +39,7 @@
#include "src/persistence/igroupsettings.h"
#include "src/persistence/settings.h"
#include <QDebug>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QRegularExpression>
@ -91,7 +92,6 @@ GroupChatForm::GroupChatForm(Core& core_, Group* chatGroup, IChatLog& chatLog_, @@ -91,7 +92,6 @@ GroupChatForm::GroupChatForm(Core& core_, Group* chatGroup, IChatLog& chatLog_,
documentCache_, smileyPack_, settings_, style_, messageBoxManager, friendList_)
, core{core_}
, group(chatGroup)
, inCall(false)
, settings(settings_)
, style{style_}
, friendList{friendList_}
@ -259,6 +259,9 @@ void GroupChatForm::onUserLeft(const ToxPk& user, const QString& name) @@ -259,6 +259,9 @@ void GroupChatForm::onUserLeft(const ToxPk& user, const QString& name)
addSystemInfoMessage(QDateTime::currentDateTime(), SystemMessageType::userLeftGroup, {name});
}
updateUserNames();
if (call) {
call->removePeer(user);
}
}
void GroupChatForm::onPeerNameChanged(const ToxPk& peer, const QString& oldName, const QString& newName)
@ -325,48 +328,38 @@ void GroupChatForm::dropEvent(QDropEvent* ev) @@ -325,48 +328,38 @@ void GroupChatForm::dropEvent(QDropEvent* ev)
void GroupChatForm::onMicMuteToggle()
{
if (audioInputFlag) {
CoreAV* av = core.getAv();
const bool oldMuteState = av->isGroupCallInputMuted(group);
const bool newMute = !oldMuteState;
av->muteCallInput(group, newMute);
headWidget->updateMuteMicButton(inCall, newMute);
const bool muteState = call->getMuteMic();
call->setMuteMic(!muteState);
headWidget->updateMuteMicButton(true, !muteState);
}
}
void GroupChatForm::onVolMuteToggle()
{
if (audioOutputFlag) {
CoreAV* av = core.getAv();
const bool oldMuteState = av->isGroupCallOutputMuted(group);
const bool newMute = !oldMuteState;
av->muteCallOutput(group, newMute);
headWidget->updateMuteVolButton(inCall, newMute);
const bool muteState = call->getMuteVol();
call->setMuteVol(!muteState);
headWidget->updateMuteVolButton(true, !muteState);
}
}
void GroupChatForm::onCallClicked()
{
CoreAV* av = core.getAv();
if (!inCall) {
joinGroupCall();
} else {
if (call) {
leaveGroupCall();
} else {
joinGroupCall();
}
headWidget->updateCallButtons(true, inCall);
const bool inMute = av->isGroupCallInputMuted(group);
headWidget->updateMuteMicButton(inCall, inMute);
const bool outMute = av->isGroupCallOutputMuted(group);
headWidget->updateMuteVolButton(inCall, outMute);
headWidget->updateCallButtons(true, call != nullptr);
headWidget->updateMuteMicButton(call != nullptr, call && call->getMuteMic());
headWidget->updateMuteVolButton(call != nullptr, call && call->getMuteVol());
}
void GroupChatForm::keyPressEvent(QKeyEvent* ev)
{
// Push to talk (CTRL+P)
if (ev->key() == Qt::Key_P && (ev->modifiers() & Qt::ControlModifier) && inCall) {
if (ev->key() == Qt::Key_P && (ev->modifiers() & Qt::ControlModifier) && (call != nullptr)) {
onMicMuteToggle();
}
@ -377,7 +370,7 @@ void GroupChatForm::keyPressEvent(QKeyEvent* ev) @@ -377,7 +370,7 @@ void GroupChatForm::keyPressEvent(QKeyEvent* ev)
void GroupChatForm::keyReleaseEvent(QKeyEvent* ev)
{
// Push to talk (CTRL+P)
if (ev->key() == Qt::Key_P && (ev->modifiers() & Qt::ControlModifier) && inCall) {
if (ev->key() == Qt::Key_P && (ev->modifiers() & Qt::ControlModifier) && (call != nullptr)) {
onMicMuteToggle();
}
@ -391,7 +384,7 @@ void GroupChatForm::keyReleaseEvent(QKeyEvent* ev) @@ -391,7 +384,7 @@ void GroupChatForm::keyReleaseEvent(QKeyEvent* ev)
void GroupChatForm::updateUserCount(int numPeers)
{
nusersLabel->setText(tr("%n user(s) in chat", "Number of users in chat", numPeers));
headWidget->updateCallButtons(true, inCall);
headWidget->updateCallButtons(true, call != nullptr);
}
void GroupChatForm::retranslateUi()
@ -458,17 +451,19 @@ void GroupChatForm::onLabelContextMenuRequested(const QPoint& localPos) @@ -458,17 +451,19 @@ void GroupChatForm::onLabelContextMenuRequested(const QPoint& localPos)
void GroupChatForm::joinGroupCall()
{
CoreAV* av = core.getAv();
av->joinGroupCall(*group);
call = av->joinGroupCall(*group);
if (!call) {
qDebug() << "Failed to join group call";
return;
}
audioInputFlag = true;
audioOutputFlag = true;
inCall = true;
}
void GroupChatForm::leaveGroupCall()
{
CoreAV* av = core.getAv();
av->leaveGroupCall(group->getId());
call.reset();
audioInputFlag = false;
audioOutputFlag = false;
inCall = false;
}

4
src/widget/form/groupchatform.h

@ -22,6 +22,8 @@ @@ -22,6 +22,8 @@
#include "genericchatform.h"
#include "src/core/toxpk.h"
#include "src/persistence/igroupsettings.h"
#include "src/core/toxcall.h"
#include "src/core/toxpk.h"
#include <QMap>
namespace Ui {
@ -87,8 +89,8 @@ private: @@ -87,8 +89,8 @@ private:
FlowLayout* namesListLayout;
QLabel* nusersLabel;
TabCompleter* tabber;
bool inCall;
Settings& settings;
Style& style;
FriendList& friendList;
std::unique_ptr<ToxGroupCall> call;
};

14
src/widget/widget.cpp

@ -1144,12 +1144,6 @@ void Widget::dispatchFileSendFailed(uint32_t friendId, const QString& fileName) @@ -1144,12 +1144,6 @@ void Widget::dispatchFileSendFailed(uint32_t friendId, const QString& fileName)
SystemMessageType::fileSendFailed, {fileName});
}
void Widget::onRejectCall(uint32_t friendId)
{
CoreAV* const av = core->getAv();
av->cancelCall(friendId);
}
void Widget::addFriend(uint32_t friendId, const ToxPk& friendPk)
{
assert(core != nullptr);
@ -1210,7 +1204,6 @@ void Widget::addFriend(uint32_t friendId, const ToxPk& friendPk) @@ -1210,7 +1204,6 @@ void Widget::addFriend(uint32_t friendId, const ToxPk& friendPk)
connect(friendForm, &ChatForm::outgoingNotification, this, &Widget::outgoingNotification);
connect(friendForm, &ChatForm::stopNotification, this, &Widget::onStopNotification);
connect(friendForm, &ChatForm::endCallNotification, this, &Widget::onCallEnd);
connect(friendForm, &ChatForm::rejectCall, this, &Widget::onRejectCall);
connect(widget, &FriendWidget::newWindowOpened, this, &Widget::openNewDialog);
connect(widget, &FriendWidget::chatroomWidgetClicked, this, &Widget::onChatroomWidgetClicked);
@ -2118,13 +2111,6 @@ Group* Widget::createGroup(uint32_t groupnumber, const GroupId& groupId) @@ -2118,13 +2111,6 @@ Group* Widget::createGroup(uint32_t groupnumber, const GroupId& groupId)
*friendList);
assert(newgroup);
if (enabled) {
connect(newgroup, &Group::userLeft, [=](const ToxPk& user){
CoreAV *av = core->getAv();
assert(av);
av->invalidateGroupCallPeerSource(*newgroup, user);
});
}
auto rawChatroom = new GroupChatroom(newgroup, contentDialogManager.get(), *core,
*friendList);
std::shared_ptr<GroupChatroom> chatroom(rawChatroom);

1
src/widget/widget.h

@ -243,7 +243,6 @@ private slots: @@ -243,7 +243,6 @@ private slots:
void outgoingNotification();
void onCallEnd();
void incomingNotification(uint32_t friendNum);
void onRejectCall(uint32_t friendId);
void onStopNotification();
void dispatchFile(ToxFile file);
void dispatchFileWithBool(ToxFile file, bool pausedOrBroken);

Loading…
Cancel
Save