diff --git a/src/core/coreav.cpp b/src/core/coreav.cpp index e81728170..5470a14ef 100644 --- a/src/core/coreav.cpp +++ b/src/core/coreav.cpp @@ -204,7 +204,11 @@ bool CoreAV::isCallStarted(const Group* g) const */ bool CoreAV::isCallActive(const Friend* f) const { - return isCallStarted(f) && calls[f->getId()].isActive(); + auto it = calls.find(f->getId()); + if (it == calls.end()) { + return false; + } + return isCallStarted(f) && it->second.isActive(); } /** @@ -214,12 +218,17 @@ bool CoreAV::isCallActive(const Friend* f) const */ bool CoreAV::isCallActive(const Group* g) const { - return isCallStarted(g) && groupCalls[g->getId()].isActive(); + auto it = groupCalls.find(g->getId()); + if (it == groupCalls.end()) { + return false; + } + return isCallStarted(g) && it->second.isActive(); } bool CoreAV::isCallVideoEnabled(const Friend* f) const { - return isCallStarted(f) && calls[f->getId()].getVideoEnabled(); + auto it = calls.find(f->getId()); + return isCallStarted(f) && it->second.getVideoEnabled(); } bool CoreAV::answerCall(uint32_t friendNum, bool video) @@ -240,17 +249,18 @@ bool CoreAV::answerCall(uint32_t friendNum, bool video) } qDebug() << QString("answering call %1").arg(friendNum); - assert(calls.find(friendNum) != calls.end()); + auto it = calls.find(friendNum); + assert(it != calls.end()); TOXAV_ERR_ANSWER err; const uint32_t videoBitrate = video ? VIDEO_DEFAULT_BITRATE : 0; if (toxav_answer(toxav, friendNum, Settings::getInstance().getAudioBitrate(), videoBitrate, &err)) { - calls[friendNum].setActive(true); + it->second.setActive(true); return true; } else { qWarning() << "Failed to answer call with error" << err; toxav_call_control(toxav, friendNum, TOXAV_CALL_CONTROL_CANCEL, nullptr); - calls.erase(friendNum); + calls.erase(it); return false; } } @@ -273,7 +283,8 @@ bool CoreAV::startCall(uint32_t friendNum, bool video) } qDebug() << QString("Starting call with %1").arg(friendNum); - if (calls.find(friendNum) != calls.end()) { + 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; } @@ -282,8 +293,8 @@ bool CoreAV::startCall(uint32_t friendNum, bool video) if (!toxav_call(toxav, friendNum, Settings::getInstance().getAudioBitrate(), videoBitrate, nullptr)) return false; - calls.insert(std::make_pair(friendNum, ToxFriendCall(friendNum, video, *this))); - calls[friendNum].startTimeout(friendNum); + auto ret = calls.insert(std::make_pair(friendNum, ToxFriendCall(friendNum, video, *this))); + ret.first->second.startTimeout(friendNum); return true; } @@ -341,13 +352,14 @@ void CoreAV::timeoutCall(uint32_t friendNum) * @return False only on error, but not if there's nothing to send. */ bool CoreAV::sendCallAudio(uint32_t callId, const int16_t* pcm, size_t samples, uint8_t chans, - uint32_t rate) + uint32_t rate) const { - if (calls.find(callId) == calls.end()) { + auto it = calls.find(callId); + if (it == calls.end()) { return false; } - ToxFriendCall& call = calls[callId]; + ToxFriendCall const& call = it->second; if (call.getMuteMic() || !call.isActive() || !(call.getState() & TOXAV_FRIEND_CALL_STATE_ACCEPTING_A)) { @@ -378,11 +390,12 @@ void CoreAV::sendCallVideo(uint32_t callId, std::shared_ptr vframe) { // We might be running in the FFmpeg thread and holding the CameraSource lock // So be careful not to deadlock with anything while toxav locks in toxav_video_send_frame - if (calls.find(callId) == calls.end()) { + auto it = calls.find(callId); + if (it == calls.end()) { return; } - ToxFriendCall& call = calls[callId]; + ToxFriendCall& call = it->second; if (!call.getVideoEnabled() || !call.isActive() || !(call.getState() & TOXAV_FRIEND_CALL_STATE_ACCEPTING_V)) { @@ -431,8 +444,9 @@ void CoreAV::sendCallVideo(uint32_t callId, std::shared_ptr vframe) */ void CoreAV::toggleMuteCallInput(const Friend* f) { - if (f && (calls.find(f->getId()) != calls.end())) { - ToxCall& call = calls[f->getId()]; + auto it = calls.find(f->getId()); + if (f && (it != calls.end())) { + ToxCall& call = it->second; call.setMuteMic(!call.getMuteMic()); } } @@ -443,8 +457,9 @@ void CoreAV::toggleMuteCallInput(const Friend* f) */ void CoreAV::toggleMuteCallOutput(const Friend* f) { - if (f && (calls.find(f->getId()) != calls.end())) { - ToxCall& call = calls[f->getId()]; + auto it = calls.find(f->getId()); + if (f && (it != calls.end())) { + ToxCall& call = it->second; call.setMuteVol(!call.getMuteVol()); } } @@ -470,11 +485,12 @@ void CoreAV::groupCallCallback(void* tox, uint32_t group, uint32_t peer, const i Core* c = static_cast(core); CoreAV* cav = c->getAv(); - if (cav->groupCalls.find(group) == cav->groupCalls.end()) { + auto it = cav->groupCalls.find(group); + if (it == cav->groupCalls.end()) { return; } - ToxGroupCall& call = cav->groupCalls[group]; + ToxGroupCall& call = it->second; emit c->groupPeerAudioPlaying(group, peer); @@ -499,11 +515,12 @@ void CoreAV::groupCallCallback(void* tox, int group, int peer, const int16_t* da Core* c = static_cast(core); CoreAV* cav = c->getAv(); - if (cav->groupCalls.find(group) == cav->groupCalls.end()) { + auto it = cav->groupCalls.find(group); + if (it == cav->groupCalls.end()) { return; } - ToxGroupCall& call = cav->groupCalls[group]; + ToxGroupCall& call = it->second; emit c->groupPeerAudioPlaying(group, peer); @@ -528,9 +545,13 @@ void CoreAV::groupCallCallback(void* tox, int group, int peer, const int16_t* da */ void CoreAV::invalidateGroupCallPeerSource(int group, int peer) { + auto it = groupCalls.find(group); + if (it == groupCalls.end()) { + return; + } Audio& audio = Audio::getInstance(); - audio.unsubscribeOutput(groupCalls[group].getPeers()[peer]); - groupCalls[group].getPeers()[peer] = 0; + audio.unsubscribeOutput(it->second.getPeers()[peer]); + it->second.getPeers()[peer] = 0; } /** @@ -548,15 +569,16 @@ void CoreAV::invalidateGroupCallSources(int group) * @param friendNum Id of friend in call list. * @return Video surface to show */ -VideoSource* CoreAV::getVideoSourceFromCall(int friendNum) +VideoSource* CoreAV::getVideoSourceFromCall(int friendNum) const { - if (calls.find(friendNum) == calls.end()) { + auto it = calls.find(friendNum); + if (it == calls.end()) { qWarning() << "CoreAV::getVideoSourceFromCall: No such call, did it die before we finished " "answering?"; return nullptr; } - return calls[friendNum].getVideoSource(); + return it->second.getVideoSource(); } /** @@ -568,8 +590,12 @@ void CoreAV::joinGroupCall(int groupId) { qDebug() << QString("Joining group call %1").arg(groupId); - groupCalls[groupId] = ToxGroupCall{groupId, *this}; - groupCalls[groupId].setActive(true); + auto ret = groupCalls.insert(std::pair(groupId, ToxGroupCall{groupId, *this})); + if (ret.second == false) { + qWarning() << "This group call already exists, not joining!"; + return; + } + ret.first->second.setActive(true); } /** @@ -585,15 +611,14 @@ void CoreAV::leaveGroupCall(int groupId) } bool CoreAV::sendGroupCallAudio(int groupId, const int16_t* pcm, size_t samples, uint8_t chans, - uint32_t rate) + uint32_t rate) const { - if (groupCalls.find(groupId) == groupCalls.end()) { + std::map::const_iterator it = groupCalls.find(groupId); + if (it == groupCalls.end()) { return false; } - ToxGroupCall& call = groupCalls[groupId]; - - if (!call.isActive() || call.getMuteMic()) { + if (!it->second.isActive() || it->second.getMuteMic()) { return true; } @@ -610,8 +635,9 @@ bool CoreAV::sendGroupCallAudio(int groupId, const int16_t* pcm, size_t samples, */ void CoreAV::muteCallInput(const Group* g, bool mute) { - if (g && (groupCalls.find(g->getId()) != groupCalls.end())) { - groupCalls[g->getId()].setMuteMic(mute); + auto it = groupCalls.find(g->getId()); + if (g && (it != groupCalls.end())) { + it->second.setMuteMic(mute); } } @@ -622,8 +648,9 @@ void CoreAV::muteCallInput(const Group* g, bool mute) */ void CoreAV::muteCallOutput(const Group* g, bool mute) { - if (g && (groupCalls.find(g->getId()) != groupCalls.end())) { - groupCalls[g->getId()].setMuteVol(mute); + auto it = groupCalls.find(g->getId()); + if (g && (it != groupCalls.end())) { + it->second.setMuteVol(mute); } } @@ -639,7 +666,8 @@ bool CoreAV::isGroupCallInputMuted(const Group* g) const } const uint32_t groupId = g->getId(); - return (groupCalls.find(groupId) != groupCalls.end()) && groupCalls[groupId].getMuteMic(); + auto it = groupCalls.find(groupId); + return (it != groupCalls.end()) && it->second.getMuteMic(); } /** @@ -654,7 +682,8 @@ bool CoreAV::isGroupCallOutputMuted(const Group* g) const } const uint32_t groupId = g->getId(); - return (groupCalls.find(groupId) != groupCalls.end()) && groupCalls[groupId].getMuteVol(); + auto it = groupCalls.find(groupId); + return (it != groupCalls.end()) && it->second.getMuteVol(); } /** @@ -691,7 +720,8 @@ bool CoreAV::isCallInputMuted(const Friend* f) const return false; } const uint32_t friendId = f->getId(); - return (calls.find(friendId) != calls.end()) && calls[friendId].getMuteMic(); + auto it = calls.find(friendId); + return (it != calls.end()) && it->second.getMuteMic(); } /** @@ -705,7 +735,8 @@ bool CoreAV::isCallOutputMuted(const Friend* f) const return false; } const uint32_t friendId = f->getId(); - return (calls.find(friendId) != calls.end()) && calls[f->getId()].getMuteVol(); + auto it = calls.find(friendId); + return (it != calls.end()) && it->second.getMuteVol(); } /** @@ -763,7 +794,8 @@ void CoreAV::callCallback(ToxAV* toxav, uint32_t friendNum, bool audio, bool vid return; } - if (self->calls.find(friendNum) != self->calls.end()) { + auto it = self->calls.insert(std::pair(friendNum, ToxFriendCall{friendNum, video, *self})); + if (it.second == false) { /// Hanging up from a callback is supposed to be UB, /// but since currently the toxav callbacks are fired from the toxcore thread, /// we'll always reach this point through a non-blocking queud connection, so not in the @@ -773,7 +805,6 @@ void CoreAV::callCallback(ToxAV* toxav, uint32_t friendNum, bool audio, bool vid return; } qDebug() << QString("Received call invite from %1").arg(friendNum); - self->calls[friendNum] = ToxFriendCall{friendNum, video, *self}; // We don't get a state callback when answering, so fill the state ourselves in advance int state = 0; @@ -781,7 +812,8 @@ void CoreAV::callCallback(ToxAV* toxav, uint32_t friendNum, bool audio, bool vid state |= TOXAV_FRIEND_CALL_STATE_SENDING_A | TOXAV_FRIEND_CALL_STATE_ACCEPTING_A; if (video) state |= TOXAV_FRIEND_CALL_STATE_SENDING_V | TOXAV_FRIEND_CALL_STATE_ACCEPTING_V; - calls[friendNum].setState(static_cast(state)); + it.first->second.setState(static_cast(state)); + // note: changed to self-> emit reinterpret_cast(self)->avInvite(friendNum, video); self->threadSwitchLock.clear(std::memory_order_release); @@ -808,21 +840,24 @@ void CoreAV::stateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t state, voi return; } - if (self->calls.find(friendNum) == self->calls.end()) { + auto it = self->calls.find(friendNum); + if (it == self->calls.end()) { qWarning() << QString("stateCallback called, but call %1 is already dead").arg(friendNum); self->threadSwitchLock.clear(std::memory_order_release); return; } - ToxFriendCall& call = self->calls[friendNum]; + ToxFriendCall& call = it->second; if (state & TOXAV_FRIEND_CALL_STATE_ERROR) { qWarning() << "Call with friend" << friendNum << "died of unnatural causes!"; calls.erase(friendNum); + // why not self-> emit self->avEnd(friendNum, true); } else if (state & TOXAV_FRIEND_CALL_STATE_FINISHED) { qDebug() << "Call with friend" << friendNum << "finished quietly"; calls.erase(friendNum); + // why not self-> emit self->avEnd(friendNum); } else { // If our state was null, we started the call and were still ringing @@ -904,11 +939,12 @@ void CoreAV::audioFrameCallback(ToxAV*, uint32_t friendNum, const int16_t* pcm, uint8_t channels, uint32_t samplingRate, void* vSelf) { CoreAV* self = static_cast(vSelf); - if (self->calls.find(friendNum) == self->calls.end()) { + auto it = calls.find(friendNum); + if (it == self->calls.end()) { return; } - ToxFriendCall& call = self->calls[friendNum]; + ToxFriendCall& call = it->second; if (call.getMuteVol()) { return; @@ -928,11 +964,12 @@ void CoreAV::videoFrameCallback(ToxAV*, uint32_t friendNum, uint16_t w, uint16_t const uint8_t* y, const uint8_t* u, const uint8_t* v, int32_t ystride, int32_t ustride, int32_t vstride, void*) { - if (calls.find(friendNum) == calls.end()) { + auto it = calls.find(friendNum); + if (it == calls.end()) { return; } - CoreVideoSource* videoSource = calls[friendNum].getVideoSource(); + CoreVideoSource* videoSource = it->second.getVideoSource(); if (!videoSource) { return; } diff --git a/src/core/coreav.h b/src/core/coreav.h index a8dbd5944..321b79ed1 100644 --- a/src/core/coreav.h +++ b/src/core/coreav.h @@ -56,12 +56,12 @@ public: bool isCallActive(const Group* g) const; bool isCallVideoEnabled(const Friend* f) const; bool sendCallAudio(uint32_t friendNum, const int16_t* pcm, size_t samples, uint8_t chans, - uint32_t rate); + uint32_t rate) const; void sendCallVideo(uint32_t friendNum, std::shared_ptr frame); bool sendGroupCallAudio(int groupNum, const int16_t* pcm, size_t samples, uint8_t chans, - uint32_t rate); + uint32_t rate) const; - VideoSource* getVideoSourceFromCall(int callNumber); + VideoSource* getVideoSourceFromCall(int callNumber) const; void invalidateCallSources(); void sendNoVideo(); diff --git a/src/core/toxcall.cpp b/src/core/toxcall.cpp index d856de0b4..21cc77fe5 100644 --- a/src/core/toxcall.cpp +++ b/src/core/toxcall.cpp @@ -28,55 +28,111 @@ * @brief Keeps sources for users in group calls. */ -using namespace std; - -ToxCall::ToxCall() - : active{false} - , muteMic{false} - , muteVol{false} +ToxCall::ToxCall(uint32_t CallId, bool VideoEnabled, CoreAV& av) + : videoEnabled{VideoEnabled} + , av{&av} { Audio& audio = Audio::getInstance(); audio.subscribeInput(); + audio.subscribeOutput(alSource); + + audioInConn = QObject::connect(&Audio::getInstance(), &Audio::frameAvailable, + [&av, CallId](const int16_t* pcm, size_t samples, uint8_t chans, + uint32_t rate) { + av.sendCallAudio(CallId, pcm, samples, chans, rate); + }); + + if (!audioInConn) { + qDebug() << "Audio connection not working"; + } + + if (videoEnabled) { + videoSource = new CoreVideoSource(); + CameraSource& source = CameraSource::getInstance(); + + if (source.isNone()) { + source.setupDefault(); + } + source.subscribe(); + videoInConn = QObject::connect(&source, &VideoSource::frameAvailable, + [&av, CallId](std::shared_ptr frame) { + av.sendCallVideo(CallId, frame); + }); + if (!videoInConn) { + qDebug() << "Video connection not working"; + } + } } -ToxCall::ToxCall(ToxCall&& other) noexcept - : audioInConn{other.audioInConn} - , active{other.active} - , muteMic{other.muteMic} - , muteVol{other.muteVol} +ToxCall::ToxCall(ToxCall&& other) noexcept : audioInConn{other.audioInConn}, + alSource{other.alSource}, + active{other.active}, + muteMic{other.muteMic}, + muteVol{other.muteVol}, + videoInConn{other.videoInConn}, + videoEnabled{other.videoEnabled}, + nullVideoBitrate{other.nullVideoBitrate}, + videoSource{other.videoSource}, + av{other.av} { + Audio& audio = Audio::getInstance(); + audio.subscribeInput(); other.audioInConn = QMetaObject::Connection(); - // invalidate object, all resources are moved - other.valid = false; + other.alSource = 0; + other.videoInConn = QMetaObject::Connection(); + other.videoEnabled = false; // we don't need to subscribe video because other won't unsubscribe + other.videoSource = nullptr; + other.av = nullptr; } ToxCall::~ToxCall() { Audio& audio = Audio::getInstance(); - // only free resources if they weren't moved - if (valid) { - QObject::disconnect(audioInConn); - audio.unsubscribeInput(); + QObject::disconnect(audioInConn); + audio.unsubscribeInput(); + audio.unsubscribeOutput(alSource); + if (videoEnabled) { + QObject::disconnect(videoInConn); + CameraSource::getInstance().unsubscribe(); + // TODO: check if async is still needed + // This destructor could be running in a toxav callback while holding toxav locks. + // If the CameraSource thread calls toxav *_send_frame, we might deadlock the toxav and + // CameraSource locks, + // so we unsuscribe asynchronously, it's fine if the webcam takes a couple milliseconds more + // to poweroff. + QtConcurrent::run([]() { CameraSource::getInstance().unsubscribe(); }); + if (videoSource) { + videoSource->setDeleteOnClose(true); + videoSource = nullptr; + } } } ToxCall& ToxCall::operator=(ToxCall&& other) noexcept { - if (valid) { - // if we're already valid, we need to cleanup our resources since we're going to inherit the resources - // that are being moved in - QObject::disconnect(audioInConn); - Audio::getInstance().unsubscribeInput(); - } + QObject::disconnect(audioInConn); audioInConn = other.audioInConn; other.audioInConn = QMetaObject::Connection(); active = other.active; muteMic = other.muteMic; muteVol = other.muteVol; - // invalidate object, all resources are moved - other.valid = false; + + alSource = other.alSource; + other.alSource = 0; + + Audio::getInstance().subscribeInput(); + + videoInConn = other.videoInConn; + other.videoInConn = QMetaObject::Connection(); + videoEnabled = other.videoEnabled; + other.videoEnabled = false; + nullVideoBitrate = other.nullVideoBitrate; + videoSource = other.videoSource; + other.videoSource = nullptr; + av = other.av; + other.av = nullptr; return *this; } @@ -111,13 +167,53 @@ void ToxCall::setMuteMic(bool value) muteMic = value; } +bool ToxCall::getVideoEnabled() const +{ + return videoEnabled; +} + +void ToxCall::setVideoEnabled(bool value) +{ + videoEnabled = value; +} + +bool ToxCall::getNullVideoBitrate() const +{ + return nullVideoBitrate; +} + +void ToxCall::setNullVideoBitrate(bool value) +{ + nullVideoBitrate = value; +} + +CoreVideoSource* ToxCall::getVideoSource() const +{ + return videoSource; +} + +quint32 ToxCall::getAlSource() const +{ + return alSource; +} + +void ToxCall::setAlSource(const quint32& value) +{ + alSource = value; +} + +ToxFriendCall::ToxFriendCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av) + : ToxCall(FriendNum, VideoEnabled, av) +{ +} + void ToxFriendCall::startTimeout(uint32_t callId) { if (!timeoutTimer) { - timeoutTimer = new QTimer(); + timeoutTimer = std::unique_ptr{new QTimer{}}; // We might move, so we need copies of members. CoreAV won't move while we're alive CoreAV* avCopy = av; - QObject::connect(timeoutTimer, &QTimer::timeout, + QObject::connect(timeoutTimer.get(), &QTimer::timeout, [avCopy, callId]() { avCopy->timeoutCall(callId); }); } @@ -131,33 +227,7 @@ void ToxFriendCall::stopTimeout() return; timeoutTimer->stop(); - delete timeoutTimer; - timeoutTimer = nullptr; -} - -bool ToxFriendCall::getVideoEnabled() const -{ - return videoEnabled; -} - -void ToxFriendCall::setVideoEnabled(bool value) -{ - videoEnabled = value; -} - -bool ToxFriendCall::getNullVideoBitrate() const -{ - return nullVideoBitrate; -} - -void ToxFriendCall::setNullVideoBitrate(bool value) -{ - nullVideoBitrate = value; -} - -CoreVideoSource* ToxFriendCall::getVideoSource() const -{ - return videoSource; + timeoutTimer.reset(); } TOXAV_FRIEND_CALL_STATE ToxFriendCall::getState() const @@ -170,127 +240,12 @@ void ToxFriendCall::setState(const TOXAV_FRIEND_CALL_STATE& value) state = value; } -quint32 ToxFriendCall::getAlSource() const -{ - return alSource; -} - -void ToxFriendCall::setAlSource(const quint32& value) -{ - alSource = value; -} - -ToxFriendCall::ToxFriendCall(uint32_t friendId, bool VideoEnabled, CoreAV& av) - : ToxCall() - , videoEnabled{VideoEnabled} - , nullVideoBitrate{false} - , videoSource{nullptr} - , state{static_cast(0)} - , av{&av} - , timeoutTimer{nullptr} -{ - Audio& audio = Audio::getInstance(); - audioInConn = QObject::connect(&audio, &Audio::frameAvailable, - [&av, friendId](const int16_t* pcm, size_t samples, - uint8_t chans, uint32_t rate) { - av.sendCallAudio(friendId, pcm, samples, chans, rate); - }); - if (!audioInConn) { - qDebug() << "Audio connection not working"; - } - - // subscribe audio output - audio.subscribeOutput(alSource); - - if (videoEnabled) { - videoSource = new CoreVideoSource; - CameraSource& source = CameraSource::getInstance(); - - if (source.isNone()) - source.setupDefault(); - source.subscribe(); - QObject::connect(&source, &VideoSource::frameAvailable, - [friendId, &av](shared_ptr frame) { - av.sendCallVideo(friendId, frame); - }); - } -} - -ToxFriendCall::ToxFriendCall(ToxFriendCall&& other) noexcept - : ToxCall(move(other)) - , alSource{other.alSource} - , videoEnabled{other.videoEnabled} - , nullVideoBitrate{other.nullVideoBitrate} - , videoSource{other.videoSource} - , state{other.state} - , av{other.av} - , timeoutTimer{other.timeoutTimer} -{ - other.videoEnabled = false; - other.videoSource = nullptr; - other.timeoutTimer = nullptr; - // TODO: wrong, because "0" could be a valid source id - other.alSource = 0; -} - -ToxFriendCall::~ToxFriendCall() -{ - if (timeoutTimer) - delete timeoutTimer; - - if (videoEnabled) { - // This destructor could be running in a toxav callback while holding toxav locks. - // If the CameraSource thread calls toxav *_send_frame, we might deadlock the toxav and - // CameraSource locks, - // so we unsuscribe asynchronously, it's fine if the webcam takes a couple milliseconds more - // to poweroff. - QtConcurrent::run([]() { CameraSource::getInstance().unsubscribe(); }); - if (videoSource) { - videoSource->setDeleteOnClose(true); - videoSource = nullptr; - } - } - if (valid) { - Audio::getInstance().unsubscribeOutput(alSource); - } -} - -ToxFriendCall& ToxFriendCall::operator=(ToxFriendCall&& other) noexcept -{ - ToxCall::operator=(move(other)); - videoEnabled = other.videoEnabled; - other.videoEnabled = false; - videoSource = other.videoSource; - other.videoSource = nullptr; - state = other.state; - timeoutTimer = other.timeoutTimer; - other.timeoutTimer = nullptr; - av = other.av; - nullVideoBitrate = other.nullVideoBitrate; - alSource = other.alSource; - // TODO: wrong, because "0" could be a valid source id - other.alSource = 0; - - return *this; -} - ToxGroupCall::ToxGroupCall(int GroupNum, CoreAV& av) - : ToxCall() + : ToxCall(static_cast(GroupNum), false, av) { - static_assert( - numeric_limits::max() >= numeric_limits::max(), - "The callId must be able to represent any group number, change its type if needed"); - - audioInConn = QObject::connect(&Audio::getInstance(), &Audio::frameAvailable, - [&av, GroupNum](const int16_t* pcm, size_t samples, - uint8_t chans, uint32_t rate) { - av.sendGroupCallAudio(GroupNum, pcm, samples, chans, rate); - }); } -ToxGroupCall::ToxGroupCall(ToxGroupCall&& other) noexcept - : ToxCall(move(other)) - , peers{other.peers} +ToxGroupCall::ToxGroupCall(ToxGroupCall&& other) noexcept : ToxCall(std::move(other)), peers{other.peers} { // all peers were moved, this ensures audio output is unsubscribed only once other.peers.clear(); @@ -307,7 +262,7 @@ ToxGroupCall::~ToxGroupCall() ToxGroupCall& ToxGroupCall::operator=(ToxGroupCall&& other) noexcept { - ToxCall::operator=(move(other)); + ToxCall::operator=(std::move(other)); peers = other.peers; other.peers.clear(); diff --git a/src/core/toxcall.h b/src/core/toxcall.h index db2677468..d4b60462c 100644 --- a/src/core/toxcall.h +++ b/src/core/toxcall.h @@ -1,6 +1,7 @@ #ifndef TOXCALL_H #define TOXCALL_H +#include #include #include #include @@ -16,7 +17,8 @@ class CoreAV; class ToxCall { protected: - explicit ToxCall(); + ToxCall() = delete; + ToxCall(uint32_t CallId, bool VideoEnabled, CoreAV& av); ~ToxCall(); public: @@ -26,7 +28,6 @@ public: ToxCall& operator=(const ToxCall& other) = delete; ToxCall& operator=(ToxCall&& other) noexcept; - bool isInactive() const; bool isActive() const; void setActive(bool value); @@ -36,27 +37,6 @@ public: bool getMuteMic() const; void setMuteMic(bool value); -protected: - QMetaObject::Connection audioInConn; - bool active; - bool muteMic; - bool muteVol; - bool valid = true; -}; - -class ToxFriendCall : public ToxCall -{ -public: - ToxFriendCall() = default; - ToxFriendCall(uint32_t friendId, bool VideoEnabled, CoreAV& av); - ToxFriendCall(ToxFriendCall&& other) noexcept; - ~ToxFriendCall(); - - ToxFriendCall& operator=(ToxFriendCall&& other) noexcept; - - void startTimeout(uint32_t callId); - void stopTimeout(); - bool getVideoEnabled() const; void setVideoEnabled(bool value); @@ -65,31 +45,50 @@ public: CoreVideoSource* getVideoSource() const; - TOXAV_FRIEND_CALL_STATE getState() const; - void setState(const TOXAV_FRIEND_CALL_STATE& value); - quint32 getAlSource() const; void setAlSource(const quint32& value); -private: - quint32 alSource; - bool videoEnabled; - bool nullVideoBitrate; - CoreVideoSource* videoSource; - TOXAV_FRIEND_CALL_STATE state; +protected: + bool active{false}; + CoreAV* av{nullptr}; + // audio + QMetaObject::Connection audioInConn; + bool muteMic{false}; + bool muteVol{false}; + quint32 alSource{0}; + // video + CoreVideoSource* videoSource{nullptr}; + QMetaObject::Connection videoInConn; + bool videoEnabled{false}; + bool nullVideoBitrate{false}; +}; + +class ToxFriendCall : public ToxCall +{ +public: + ToxFriendCall() = delete; + ToxFriendCall(uint32_t friendId, bool VideoEnabled, CoreAV& av); + ToxFriendCall(ToxFriendCall&& other) noexcept = default; + ToxFriendCall& operator=(ToxFriendCall&& other) noexcept = default; + + void startTimeout(uint32_t callId); + void stopTimeout(); + + TOXAV_FRIEND_CALL_STATE getState() const; + void setState(const TOXAV_FRIEND_CALL_STATE& value); protected: - CoreAV* av; - QTimer* timeoutTimer; + std::unique_ptr timeoutTimer; private: + TOXAV_FRIEND_CALL_STATE state{TOXAV_FRIEND_CALL_STATE_NONE}; static constexpr int CALL_TIMEOUT = 45000; }; class ToxGroupCall : public ToxCall { public: - ToxGroupCall() = default; + ToxGroupCall() = delete; ToxGroupCall(int GroupNum, CoreAV& av); ToxGroupCall(ToxGroupCall&& other) noexcept; ~ToxGroupCall(); diff --git a/src/video/corevideosource.h b/src/video/corevideosource.h index 1eb92245c..d546cb784 100644 --- a/src/video/corevideosource.h +++ b/src/video/corevideosource.h @@ -50,7 +50,7 @@ private: std::atomic_bool stopped; friend class CoreAV; - friend class ToxFriendCall; + friend class ToxCall; }; #endif // COREVIDEOSOURCE_H