From f45256baf161a6072062c6df3bcfb0aa026144b0 Mon Sep 17 00:00:00 2001 From: tux3 Date: Mon, 5 Oct 2015 02:36:50 +0200 Subject: [PATCH] Implement group calls --- qtox.pro | 6 +- src/audio/audio.cpp | 38 ++++-- src/audio/audio.h | 3 + src/core/core.cpp | 2 +- src/core/coreav.cpp | 260 ++++++++++-------------------------- src/core/coreav.h | 53 +------- src/core/toxcall.cpp | 176 ++++++++++++++++++++++++ src/core/toxcall.h | 77 +++++++++++ src/video/corevideosource.h | 2 +- 9 files changed, 365 insertions(+), 252 deletions(-) create mode 100644 src/core/toxcall.cpp create mode 100644 src/core/toxcall.h diff --git a/qtox.pro b/qtox.pro index bb4d3a222..8d961d8c8 100644 --- a/qtox.pro +++ b/qtox.pro @@ -501,7 +501,8 @@ SOURCES += \ src/widget/tool/movablewidget.cpp \ src/widget/tool/micfeedbackwidget.cpp \ src/widget/tool/removefrienddialog.cpp \ - src/video/groupnetcamview.cpp + src/video/groupnetcamview.cpp \ + src/core/toxcall.cpp HEADERS += \ src/audio/audio.h \ @@ -553,4 +554,5 @@ HEADERS += \ src/widget/tool/movablewidget.h \ src/video/genericnetcamview.h \ src/video/groupnetcamview.h \ - src/core/indexedlist.h + src/core/indexedlist.h \ + src/core/toxcall.h diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index b2db918c5..cd7624680 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -114,13 +114,10 @@ void Audio::setOutputVolume(qreal volume) for (const ToxGroupCall& call : CoreAV::groupCalls) { - if (!call.active) - continue; - for (ALuint source : call.alSources) - alSourcef(source, AL_GAIN, outputVolume); + alSourcef(call.alSource, AL_GAIN, outputVolume); } - for (const ToxCall& call : CoreAV::calls) + for (const ToxFriendCall& call : CoreAV::calls) { alSourcef(call.alSource, AL_GAIN, outputVolume); } @@ -392,15 +389,18 @@ void Audio::playGroupAudio(int group, int peer, const int16_t* data, assert(QThread::currentThread() == audioThread); QMutexLocker lock(&audioOutLock); - ToxGroupCall& call = CoreAV::groupCalls[group]; - - if (!call.active || call.muteVol) + if (!CoreAV::groupCalls.contains(group)) return; - if (!call.alSources.contains(peer)) + ToxGroupCall& call = CoreAV::groupCalls[group]; + + if (call.inactive || call.muteVol) + return; + + if (!call.alSource) { - alGenSources(1, &call.alSources[peer]); - alSourcef(call.alSources[peer], AL_GAIN, outputVolume); + alGenSources(1, &call.alSource); + alSourcef(call.alSource, AL_GAIN, outputVolume); } qreal volume = 0.; @@ -410,7 +410,7 @@ void Audio::playGroupAudio(int group, int peer, const int16_t* data, emit groupAudioPlayed(group, peer, volume / bufsize); - playAudioBuffer(call.alSources[peer], data, samples, channels, sample_rate); + playAudioBuffer(call.alSource, data, samples, channels, sample_rate); } void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate) @@ -471,6 +471,20 @@ bool Audio::isOutputClosed() return alOutDev; } +void Audio::createSource(ALuint* source) +{ + alGenSources(1, source); + alSourcef(*source, AL_GAIN, getInstance().outputVolume); +} + +void Audio::deleteSource(ALuint* source) +{ + if (alIsSource(*source)) + alDeleteSources(1, source); + else + qWarning() << "Trying to delete invalid audio source"<<*source; +} + /** Does nothing and return false on failure */ diff --git a/src/audio/audio.h b/src/audio/audio.h index d7dfd6333..0266e6677 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -72,6 +72,9 @@ public: bool isInputReady(); bool isOutputClosed(); + static void createSource(ALuint* source); + static void deleteSource(ALuint* source); + void playMono16Sound(const QByteArray& data); bool tryCaptureSamples(int16_t *buf, int samples); diff --git a/src/core/core.cpp b/src/core/core.cpp index 008529c09..4285fd8e9 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -728,7 +728,7 @@ void Core::removeGroup(int groupId, bool fake) tox_del_groupchat(tox, groupId); - if (av->groupCalls[groupId].active) + if (!av->groupCalls[groupId].inactive) av->leaveGroupCall(groupId); } diff --git a/src/core/coreav.cpp b/src/core/coreav.cpp index 863902b48..6dc38786a 100644 --- a/src/core/coreav.cpp +++ b/src/core/coreav.cpp @@ -20,121 +20,21 @@ #include "core.h" #include "coreav.h" -#include "src/video/camerasource.h" -#include "src/video/corevideosource.h" -#include "src/video/videoframe.h" #include "src/audio/audio.h" +#include "src/persistence/settings.h" +#include "src/video/videoframe.h" +#include "src/video/corevideosource.h" +#include +#include + #ifdef QTOX_FILTER_AUDIO #include "src/audio/audiofilterer.h" #endif -#include "src/persistence/settings.h" -#include -#include -#include -IndexedList CoreAV::calls; -QHash CoreAV::groupCalls; +IndexedList CoreAV::calls; +IndexedList CoreAV::groupCalls; -ToxCall::ToxCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av) - : sendAudioTimer{new QTimer}, friendNum{FriendNum}, - ringing{true}, muteMic{false}, muteVol{false}, - videoEnabled{VideoEnabled}, - alSource{0}, videoSource{nullptr}, - state{static_cast(0)} -{ - Audio::getInstance().subscribeInput(); - sendAudioTimer->setInterval(5); - sendAudioTimer->setSingleShot(true); - QObject::connect(sendAudioTimer, &QTimer::timeout, [FriendNum,&av](){av.sendCallAudio(FriendNum);}); - sendAudioTimer->start(); - - if (videoEnabled) - { - videoSource = new CoreVideoSource; - CameraSource& source = CameraSource::getInstance(); - if (!source.isOpen()) - source.open(); - source.subscribe(); - QObject::connect(&source, &VideoSource::frameAvailable, - [FriendNum,&av](std::shared_ptr frame){av.sendCallVideo(FriendNum,frame);}); - } - - -#ifdef QTOX_FILTER_AUDIO - if (Settings::getInstance().getFilterAudio()) - { - filterer = new AudioFilterer(); - filterer->startFilter(AUDIO_SAMPLE_RATE); - } - else - { - filterer = nullptr; - } -#endif -} - -ToxCall::ToxCall(ToxCall&& other) - : sendAudioTimer{other.sendAudioTimer}, friendNum{other.friendNum}, - ringing{other.ringing}, muteMic{other.muteMic}, muteVol{other.muteVol}, - videoEnabled{other.videoEnabled}, - alSource{other.alSource}, videoSource{other.videoSource}, - state{other.state} -{ - other.sendAudioTimer = nullptr; - other.friendNum = std::numeric_limits::max(); - other.videoEnabled = false; - other.alSource = 0; - other.videoSource = nullptr; - -#ifdef QTOX_FILTER_AUDIO - filterer = other.filterer; - other.filterer = nullptr; -#endif -} - -ToxCall::~ToxCall() -{ - if (sendAudioTimer) - { - QObject::disconnect(sendAudioTimer, nullptr, nullptr, nullptr); - sendAudioTimer->stop(); - Audio::getInstance().unsubscribeInput(); - } - if (videoEnabled) - { - CameraSource::getInstance().unsubscribe(); - if (videoSource) - { - videoSource->setDeleteOnClose(true); - videoSource = nullptr; - } - } -} - -const ToxCall& ToxCall::operator=(ToxCall&& other) -{ - sendAudioTimer = other.sendAudioTimer; - other.sendAudioTimer = nullptr; - friendNum = other.friendNum; - other.friendNum = std::numeric_limits::max(); - ringing = other.ringing; - muteMic = other.muteMic; - muteVol = other.muteVol; - videoEnabled = other.videoEnabled; - other.videoEnabled = false; - alSource = other.alSource; - other.alSource = 0; - videoSource = other.videoSource; - other.videoSource = nullptr; - state = other.state; - - #ifdef QTOX_FILTER_AUDIO - filterer = other.filterer; - other.filterer = nullptr; - #endif - - return *this; -} +using namespace std; CoreAV::CoreAV(Tox *tox) { @@ -150,8 +50,8 @@ CoreAV::CoreAV(Tox *tox) CoreAV::~CoreAV() { - for (const ToxCall& call : calls) - cancelCall(call.friendNum); + for (const ToxFriendCall& call : calls) + cancelCall(call.callId); toxav_kill(toxav); } @@ -177,7 +77,7 @@ void CoreAV::answerCall(uint32_t friendNum) TOXAV_ERR_ANSWER err; if (toxav_answer(toxav, friendNum, AUDIO_DEFAULT_BITRATE, VIDEO_DEFAULT_BITRATE, &err)) { - calls[friendNum].ringing = false; + calls[friendNum].inactive = false; emit avStart(friendNum, calls[friendNum].videoEnabled); } else @@ -209,19 +109,18 @@ void CoreAV::cancelCall(uint32_t friendId) calls.remove(friendId); } -void CoreAV::sendCallAudio(uint32_t callId) +bool CoreAV::sendCallAudio(uint32_t callId) { if (!calls.contains(callId)) - return; + return false; - ToxCall& call = calls[callId]; + ToxFriendCall& call = calls[callId]; - if (call.muteMic || call.ringing + if (call.muteMic || call.inactive || !(call.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A) || !Audio::getInstance().isInputReady()) { - call.sendAudioTimer->start(); - return; + return true; } int16_t buf[AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS] = {0}; @@ -252,27 +151,17 @@ void CoreAV::sendCallAudio(uint32_t callId) qDebug() << "toxav_audio_send_frame error"; } - call.sendAudioTimer->start(); + return true; } -void CoreAV::playCallVideo(void*, int32_t callId, const vpx_image *img, void *user_data) -{ - Q_UNUSED(user_data); - - if (!calls.contains(callId) || !calls[callId].videoEnabled) - return; - - calls[callId].videoSource->pushFrame(img); -} - -void CoreAV::sendCallVideo(uint32_t callId, std::shared_ptr vframe) +void CoreAV::sendCallVideo(uint32_t callId, shared_ptr vframe) { if (!calls.contains(callId)) return; - ToxCall& call = calls[callId]; + ToxFriendCall& call = calls[callId]; - if (!call.videoEnabled || call.ringing + if (!call.videoEnabled || call.inactive || !(call.state & TOXAV_FRIEND_CALL_STATE_ACCEPTING_V)) return; @@ -313,65 +202,57 @@ VideoSource *CoreAV::getVideoSourceFromCall(int friendNum) void CoreAV::joinGroupCall(int groupId) { qDebug() << QString("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 - // Audio - Audio::getInstance().subscribeInput(); - - // Go - groupCalls[groupId].sendAudioTimer = new QTimer(); - 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(); + auto call = groupCalls.insert({groupId, *this}); + call->inactive = false; } void CoreAV::leaveGroupCall(int groupId) { qDebug() << QString("Leaving group call %1").arg(groupId); - groupCalls[groupId].active = false; - disconnect(groupCalls[groupId].sendAudioTimer,0,0,0); - groupCalls[groupId].sendAudioTimer->stop(); - for (ALuint source : groupCalls[groupId].alSources) - alDeleteSources(1, &source); - groupCalls[groupId].alSources.clear(); - Audio::getInstance().unsubscribeInput(); - delete groupCalls[groupId].sendAudioTimer; + + groupCalls.remove(groupId); } -void CoreAV::sendGroupCallAudio(int groupId, ToxAV *toxav) +bool CoreAV::sendGroupCallAudio(int groupId) { - if (!groupCalls[groupId].active) - return; + if (!groupCalls.contains(groupId)) + return false; - if (groupCalls[groupId].muteMic || !Audio::getInstance().isInputReady()) + ToxGroupCall& call = groupCalls[groupId]; + + if (call.inactive || call.muteMic || !Audio::getInstance().isInputReady()) + return true; + + int16_t buf[AUDIO_FRAME_SAMPLE_COUNT * AUDIO_CHANNELS] = {0}; + if (Audio::getInstance().tryCaptureSamples(buf, AUDIO_FRAME_SAMPLE_COUNT)) { - groupCalls[groupId].sendAudioTimer->start(); - return; - } - -#if 0 - const int framesize = (groupCalls[groupId].codecSettings.audio_frame_duration * groupCalls[groupId].codecSettings.audio_sample_rate) / 1000 * av_DefaultSettings.audio_channels; - const int bufsize = framesize * 2 * av_DefaultSettings.audio_channels; - uint8_t buf[bufsize]; - - if (Audio::getInstance().tryCaptureSamples(buf, framesize)) - { - if (toxav_group_send_audio(toxav_get_tox(toxav), groupId, (int16_t*)buf, - framesize, av_DefaultSettings.audio_channels, av_DefaultSettings.audio_sample_rate) < 0) +#ifdef QTOX_FILTER_AUDIO + if (Settings::getInstance().getFilterAudio()) { - qDebug() << "toxav_group_send_audio error"; - groupCalls[groupId].sendAudioTimer->start(); - return; + if (!call.filterer) + { + call.filterer = new AudioFilterer(); + call.filterer->startFilter(AUDIO_SAMPLE_RATE); + } + // is a null op #ifndef ALC_LOOPBACK_CAPTURE_SAMPLES + Audio::getEchoesToFilter(call.filterer, AUDIO_FRAME_SAMPLE_COUNT); + + call.filterer->filterAudio(buf, AUDIO_FRAME_SAMPLE_COUNT); + } + else if (call.filterer) + { + delete call.filterer; + call.filterer = nullptr; } - } #endif - groupCalls[groupId].sendAudioTimer->start(); + + if (toxav_group_send_audio(toxav_get_tox(toxav), groupId, buf, AUDIO_FRAME_SAMPLE_COUNT, + AUDIO_CHANNELS, AUDIO_SAMPLE_RATE) != 0) + qDebug() << "toxav_group_send_audio error"; + } + + return true; } void CoreAV::disableGroupCallMic(int groupId) @@ -413,20 +294,19 @@ void CoreAV::resetCallSources() { for (ToxGroupCall& call : groupCalls) { - for (ALuint source : call.alSources) - alDeleteSources(1, &source); - call.alSources.clear(); + if (call.alSource) + { + Audio::deleteSource(&call.alSource); + Audio::createSource(&call.alSource); + } } - for (ToxCall& call : calls) + for (ToxFriendCall& call : calls) { if (call.alSource) { - ALuint tmp = call.alSource; - call.alSource = 0; - alDeleteSources(1, &tmp); - - alGenSources(1, &call.alSource); + Audio::deleteSource(&call.alSource); + Audio::createSource(&call.alSource); } } } @@ -452,7 +332,7 @@ void CoreAV::stateCallback(ToxAV *, uint32_t friendNum, uint32_t state, void *_s CoreAV* self = static_cast(_self); assert(self->calls.contains(friendNum)); - ToxCall& call = self->calls[friendNum]; + ToxFriendCall& call = self->calls[friendNum]; if (state & TOXAV_FRIEND_CALL_STATE_ERROR) { @@ -467,10 +347,10 @@ void CoreAV::stateCallback(ToxAV *, uint32_t friendNum, uint32_t state, void *_s } else { - // If our state was null, we started the call and still ringing + // If our state was null, we started the call and were still ringing if (!call.state && state) { - call.ringing = false; + call.inactive = false; emit self->avStart(friendNum, call.videoEnabled); } @@ -523,6 +403,6 @@ void CoreAV::videoFrameCallback(ToxAV *, uint32_t friendNum, uint16_t w, uint16_ frame.stride[1] = ustride; frame.stride[2] = vstride; - ToxCall& call = calls[friendNum]; + ToxFriendCall& call = calls[friendNum]; call.videoSource->pushFrame(&frame); } diff --git a/src/core/coreav.h b/src/core/coreav.h index e21345d3d..8e6469d9e 100644 --- a/src/core/coreav.h +++ b/src/core/coreav.h @@ -21,10 +21,8 @@ #ifndef COREAV_H #define COREAV_H -#include -#include +#include #include -#include #include #if defined(__APPLE__) && defined(__MACH__) @@ -35,7 +33,7 @@ #include #endif -#include "src/core/indexedlist.h" +#include "src/core/toxcall.h" #ifdef QTOX_FILTER_AUDIO class AudioFilterer; @@ -49,43 +47,7 @@ class VideoFrame; class CoreAV; struct vpx_image; -struct ToxCall -{ - ToxCall() = default; - ToxCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av); - ToxCall(const ToxCall& other) = delete; - ToxCall(ToxCall&& other) noexcept; - ~ToxCall(); - - inline operator int() {return friendNum;} - const ToxCall& operator=(const ToxCall& other) = delete; - const ToxCall& operator=(ToxCall&& other) noexcept; - - QTimer* sendAudioTimer; - uint32_t friendNum; - bool ringing; ///< True while we're ringing and the call hasn't started yet - bool muteMic; - bool muteVol; - bool videoEnabled; ///< True if our user asked for a video call, sending and recving - ALuint alSource; - CoreVideoSource* videoSource; - TOXAV_FRIEND_CALL_STATE state; ///< State of the peer (not ours!) -#ifdef QTOX_FILTER_AUDIO - AudioFilterer* filterer; -#endif -}; - -struct ToxGroupCall -{ - QTimer *sendAudioTimer; - int groupId; - bool active = false; - bool muteMic; - bool muteVol; - QHash alSources; -}; - -class CoreAV : public QThread +class CoreAV : public QObject { Q_OBJECT @@ -100,12 +62,11 @@ public: bool anyActiveCalls(); ///< true is any calls are currently active (note: a call about to start is not yet active) void prepareCall(uint32_t friendId, ToxAV *toxav, bool videoEnabled); void cleanupCall(uint32_t friendId); - void sendCallAudio(uint32_t friendId); + bool sendCallAudio(uint32_t friendId); ///< Returns false only on error, but not if there's nothing to send void playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate); - void playCallVideo(void *toxav, int32_t callId, const vpx_image* img, void *user_data); void sendCallVideo(uint32_t friendId, std::shared_ptr frame); - void sendGroupCallAudio(int groupId, ToxAV* toxav); + bool sendGroupCallAudio(int groupId); VideoSource* getVideoSourceFromCall(int callNumber); ///< Get a call's video source void resetCallSources(); ///< Forces to regenerate each call's audio sources @@ -160,8 +121,8 @@ private: private: ToxAV* toxav; - static IndexedList calls; - static QHash groupCalls; // Maps group IDs to ToxGroupCalls + static IndexedList calls; + static IndexedList groupCalls; // Maps group IDs to ToxGroupCalls friend class Audio; friend class Core; diff --git a/src/core/toxcall.cpp b/src/core/toxcall.cpp new file mode 100644 index 000000000..e1d45829e --- /dev/null +++ b/src/core/toxcall.cpp @@ -0,0 +1,176 @@ +#include "src/audio/audio.h" +#include "src/core/toxcall.h" +#include "src/core/coreav.h" +#include "src/persistence/settings.h" +#include "src/video/camerasource.h" +#include "src/video/corevideosource.h" +#include + +#ifdef QTOX_FILTER_AUDIO +#include "src/audio/audiofilterer.h" +#endif + +using namespace std; + +ToxCall::ToxCall(uint32_t CallId) + : sendAudioTimer{new QTimer}, callId{CallId}, + inactive{true}, muteMic{false}, muteVol{false}, alSource{0} +{ + sendAudioTimer->setInterval(5); + sendAudioTimer->setSingleShot(true); + + Audio::getInstance().subscribeInput(); + +#ifdef QTOX_FILTER_AUDIO + if (Settings::getInstance().getFilterAudio()) + { + filterer = new AudioFilterer(); + filterer->startFilter(AUDIO_SAMPLE_RATE); + } + else + { + filterer = nullptr; + } +#endif +} + +ToxCall::ToxCall(ToxCall&& other) + : sendAudioTimer{other.sendAudioTimer}, callId{other.callId}, + inactive{other.inactive}, muteMic{other.muteMic}, muteVol{other.muteVol}, + alSource{other.alSource} +{ + other.sendAudioTimer = nullptr; + other.callId = numeric_limits::max(); + other.alSource = 0; + +#ifdef QTOX_FILTER_AUDIO + filterer = other.filterer; + other.filterer = nullptr; +#endif +} + +ToxCall::~ToxCall() +{ + if (sendAudioTimer) + { + QObject::disconnect(sendAudioTimer, nullptr, nullptr, nullptr); + sendAudioTimer->stop(); + Audio::getInstance().unsubscribeInput(); + } + + if (alSource) + Audio::deleteSource(&alSource); + +#ifdef QTOX_FILTER_AUDIO + if (filterer) + delete filterer; +#endif +} + +const ToxCall& ToxCall::operator=(ToxCall&& other) +{ + sendAudioTimer = other.sendAudioTimer; + other.sendAudioTimer = nullptr; + callId = other.callId; + other.callId = numeric_limits::max(); + inactive = other.inactive; + muteMic = other.muteMic; + muteVol = other.muteVol; + alSource = other.alSource; + other.alSource = 0; + + #ifdef QTOX_FILTER_AUDIO + filterer = other.filterer; + other.filterer = nullptr; + #endif + + return *this; +} + +ToxFriendCall::ToxFriendCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av) + : ToxCall(FriendNum), + videoEnabled{VideoEnabled}, videoSource{nullptr}, + state{static_cast(0)} +{ + auto audioTimerCopy = sendAudioTimer; // this might change after a move, but not sendAudioTimer + QObject::connect(sendAudioTimer, &QTimer::timeout, [FriendNum,&av,audioTimerCopy]() + { + // If sendCallAudio returns false, there was a serious error and we might as well stop the timer + if (av.sendCallAudio(FriendNum)) + audioTimerCopy->start(); + }); + sendAudioTimer->start(); + + if (videoEnabled) + { + videoSource = new CoreVideoSource; + CameraSource& source = CameraSource::getInstance(); + if (!source.isOpen()) + source.open(); + source.subscribe(); + QObject::connect(&source, &VideoSource::frameAvailable, + [FriendNum,&av](shared_ptr frame){av.sendCallVideo(FriendNum,frame);}); + } +} + +ToxFriendCall::ToxFriendCall(ToxFriendCall&& other) + : ToxCall(move(other)), + videoEnabled{other.videoEnabled}, videoSource{other.videoSource}, + state{other.state} +{ + other.videoEnabled = false; + other.videoSource = nullptr; +} + +ToxFriendCall::~ToxFriendCall() +{ + if (videoEnabled) + { + CameraSource::getInstance().unsubscribe(); + if (videoSource) + { + videoSource->setDeleteOnClose(true); + videoSource = nullptr; + } + } +} + +const ToxFriendCall& ToxFriendCall::operator=(ToxFriendCall&& other) +{ + ToxCall::operator =(move(other)); + videoEnabled = other.videoEnabled; + other.videoEnabled = false; + videoSource = other.videoSource; + other.videoSource = nullptr; + state = other.state; + + return *this; +} + +ToxGroupCall::ToxGroupCall(int GroupNum, CoreAV &av) + : ToxCall(static_cast(GroupNum)) +{ + static_assert(numeric_limits::max() >= numeric_limits::max(), + "The callId must be able to represent any group number, change its type if needed"); + + auto audioTimerCopy = sendAudioTimer; // this might change after a move, but not sendAudioTimer + QObject::connect(sendAudioTimer, &QTimer::timeout, [GroupNum,&av,audioTimerCopy]() + { + // If sendGroupCallAudio returns false, there was a serious error and we might as well stop the timer + if (av.sendGroupCallAudio(GroupNum)) + audioTimerCopy->start(); + }); + sendAudioTimer->start(); +} + +ToxGroupCall::ToxGroupCall(ToxGroupCall&& other) + : ToxCall(move(other)) +{ +} + +const ToxGroupCall &ToxGroupCall::operator=(ToxGroupCall &&other) +{ + ToxCall::operator =(move(other)); + + return *this; +} diff --git a/src/core/toxcall.h b/src/core/toxcall.h new file mode 100644 index 000000000..658b8d8d6 --- /dev/null +++ b/src/core/toxcall.h @@ -0,0 +1,77 @@ +#ifndef TOXCALL_H +#define TOXCALL_H + +#include +#include "src/core/indexedlist.h" + +#if defined(__APPLE__) && defined(__MACH__) + #include + #include +#else + #include + #include +#endif + +#include + +class QTimer; +class AudioFilterer; +class CoreVideoSource; +class CoreAV; + +struct ToxCall +{ +protected: + ToxCall() = default; + ToxCall(uint32_t CallId); + ~ToxCall(); +public: + ToxCall(const ToxCall& other) = delete; + ToxCall(ToxCall&& other) noexcept; + + inline operator int() {return callId;} + const ToxCall& operator=(const ToxCall& other) = delete; + const ToxCall& operator=(ToxCall&& other) noexcept; + +protected: + QTimer* sendAudioTimer; + +public: + uint32_t callId; ///< Could be a friendNum or groupNum, must uniquely identify the call + bool inactive; ///< True while we're not participating. (stopped group call, ringing but hasn't started yet, ...) + bool muteMic; + bool muteVol; + ALuint alSource; + +#ifdef QTOX_FILTER_AUDIO + AudioFilterer* filterer; +#endif +}; + +struct ToxFriendCall : public ToxCall +{ + ToxFriendCall() = default; + ToxFriendCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av); + ToxFriendCall(ToxFriendCall&& other) noexcept; + ~ToxFriendCall(); + + const ToxFriendCall& operator=(ToxFriendCall&& other) noexcept; + + bool videoEnabled; ///< True if our user asked for a video call, sending and recving + CoreVideoSource* videoSource; + TOXAV_FRIEND_CALL_STATE state; ///< State of the peer (not ours!) +}; + +struct ToxGroupCall : public ToxCall +{ + ToxGroupCall() = default; + ToxGroupCall(int GroupNum, CoreAV& av); + ToxGroupCall(ToxGroupCall&& other) noexcept; + + const ToxGroupCall& operator=(ToxGroupCall&& other) noexcept; + + // If you add something here, don't forget to override the ctors and move operators! +}; + +#endif // TOXCALL_H + diff --git a/src/video/corevideosource.h b/src/video/corevideosource.h index 9a290c38d..2f2e49210 100644 --- a/src/video/corevideosource.h +++ b/src/video/corevideosource.h @@ -50,7 +50,7 @@ private: std::atomic_bool biglock; ///< Fast lock friend class CoreAV; -friend struct ToxCall; +friend struct ToxFriendCall; }; #endif // COREVIDEOSOURCE_H