mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Better data structure for tox calls
This commit is contained in:
parent
512dc8de2d
commit
2b888ddc05
3
qtox.pro
3
qtox.pro
|
@ -552,4 +552,5 @@ HEADERS += \
|
|||
src/widget/tool/removefrienddialog.h \
|
||||
src/widget/tool/movablewidget.h \
|
||||
src/video/genericnetcamview.h \
|
||||
src/video/groupnetcamview.h
|
||||
src/video/groupnetcamview.h \
|
||||
src/core/indexedlist.h
|
||||
|
|
|
@ -417,7 +417,7 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u
|
|||
{
|
||||
assert(channels == 1 || channels == 2);
|
||||
|
||||
QMutexLocker lock(&audioOutLock);
|
||||
QMutexLocker lock(&getInstance().audioOutLock);
|
||||
|
||||
ALuint bufid;
|
||||
ALint processed = 0, queued = 16;
|
||||
|
@ -448,7 +448,7 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u
|
|||
|
||||
ALint state;
|
||||
alGetSourcei(alSource, AL_SOURCE_STATE, &state);
|
||||
alSourcef(alSource, AL_GAIN, outputVolume);
|
||||
alSourcef(alSource, AL_GAIN, getInstance().outputVolume);
|
||||
if (state != AL_PLAYING)
|
||||
alSourcePlay(alSource);
|
||||
}
|
||||
|
|
|
@ -69,6 +69,8 @@ public:
|
|||
void playMono16Sound(const QByteArray& data);
|
||||
bool tryCaptureSamples(uint8_t* buf, int framesize);
|
||||
|
||||
static void playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate);
|
||||
|
||||
static void playGroupAudioQueued(void *, int group, int peer, const int16_t* data,
|
||||
unsigned samples, uint8_t channels, unsigned sample_rate, void*);
|
||||
|
||||
|
@ -90,8 +92,6 @@ private:
|
|||
Audio();
|
||||
~Audio();
|
||||
|
||||
void playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate);
|
||||
|
||||
private:
|
||||
static Audio* instance;
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
|
||||
QHash<uint32_t, ToxCall> CoreAV::calls;
|
||||
IndexedList<ToxCall> CoreAV::calls;
|
||||
QHash<int, ToxGroupCall> CoreAV::groupCalls;
|
||||
|
||||
ToxCall::ToxCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av)
|
||||
|
@ -71,10 +71,32 @@ ToxCall::ToxCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av)
|
|||
#endif
|
||||
}
|
||||
|
||||
ToxCall::ToxCall(ToxCall&& other)
|
||||
: sendAudioTimer{other.sendAudioTimer}, friendNum{other.friendNum},
|
||||
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<decltype(friendNum)>::max();
|
||||
other.alSource = 0;
|
||||
other.videoSource = nullptr;
|
||||
|
||||
#ifdef QTOX_FILTER_AUDIO
|
||||
filterer = other.filterer;
|
||||
other.filterer = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
ToxCall::~ToxCall()
|
||||
{
|
||||
QObject::disconnect(sendAudioTimer, nullptr, nullptr, nullptr);
|
||||
sendAudioTimer->stop();
|
||||
if (sendAudioTimer)
|
||||
{
|
||||
QObject::disconnect(sendAudioTimer, nullptr, nullptr, nullptr);
|
||||
sendAudioTimer->stop();
|
||||
Audio::getInstance().unsubscribeInput();
|
||||
}
|
||||
if (videoEnabled)
|
||||
{
|
||||
CameraSource::getInstance().unsubscribe();
|
||||
|
@ -84,8 +106,29 @@ ToxCall::~ToxCall()
|
|||
videoSource = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Audio::getInstance().unsubscribeInput();
|
||||
const ToxCall& ToxCall::operator=(ToxCall&& other)
|
||||
{
|
||||
sendAudioTimer = other.sendAudioTimer;
|
||||
other.sendAudioTimer = nullptr;
|
||||
friendNum = other.friendNum;
|
||||
other.friendNum = std::numeric_limits<decltype(friendNum)>::max();
|
||||
muteMic = other.muteMic;
|
||||
muteVol = other.muteVol;
|
||||
videoEnabled = other.videoEnabled;
|
||||
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;
|
||||
}
|
||||
|
||||
CoreAV::CoreAV(Tox *tox)
|
||||
|
@ -102,7 +145,7 @@ CoreAV::CoreAV(Tox *tox)
|
|||
|
||||
CoreAV::~CoreAV()
|
||||
{
|
||||
for (ToxCall call : calls)
|
||||
for (const ToxCall& call : calls)
|
||||
cancelCall(call.friendNum);
|
||||
toxav_kill(toxav);
|
||||
}
|
||||
|
@ -150,7 +193,7 @@ void CoreAV::startCall(uint32_t friendId, bool video)
|
|||
return;
|
||||
}
|
||||
|
||||
calls.insert(friendId, {friendId, video, *this});
|
||||
calls.insert({friendId, video, *this});
|
||||
emit avRinging(friendId, video);
|
||||
}
|
||||
|
||||
|
@ -178,6 +221,7 @@ void CoreAV::playCallAudio(void* toxav, int32_t callId, const int16_t *data, uin
|
|||
|
||||
void CoreAV::sendCallAudio(uint32_t callId)
|
||||
{
|
||||
qDebug() << "SEND CALL AUDIO CALLED";
|
||||
if (!calls.contains(callId))
|
||||
return;
|
||||
|
||||
|
@ -283,52 +327,6 @@ void CoreAV::volMuteToggle(uint32_t callId)
|
|||
calls[callId].muteVol = !calls[callId].muteVol;
|
||||
}
|
||||
|
||||
// This function's logic was shamelessly stolen from uTox
|
||||
void CoreAV::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate)
|
||||
{
|
||||
if (!channels || channels > 2)
|
||||
{
|
||||
qWarning() << "playAudioBuffer: trying to play on "<<channels<<" channels! Giving up.";
|
||||
return;
|
||||
}
|
||||
|
||||
ALuint bufid;
|
||||
ALint processed = 0, queued = 16;
|
||||
alGetSourcei(alSource, AL_BUFFERS_PROCESSED, &processed);
|
||||
alGetSourcei(alSource, AL_BUFFERS_QUEUED, &queued);
|
||||
alSourcei(alSource, AL_LOOPING, AL_FALSE);
|
||||
|
||||
if (processed)
|
||||
{
|
||||
ALuint bufids[processed];
|
||||
alSourceUnqueueBuffers(alSource, processed, bufids);
|
||||
alDeleteBuffers(processed - 1, bufids + 1);
|
||||
bufid = bufids[0];
|
||||
}
|
||||
else if (queued < 32)
|
||||
{
|
||||
alGenBuffers(1, &bufid);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Dropped audio frame";
|
||||
return;
|
||||
}
|
||||
|
||||
alBufferData(bufid, (channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, data,
|
||||
samples * 2 * channels, sampleRate);
|
||||
alSourceQueueBuffers(alSource, 1, &bufid);
|
||||
|
||||
ALint state;
|
||||
alGetSourcei(alSource, AL_SOURCE_STATE, &state);
|
||||
alSourcef(alSource, AL_GAIN, Audio::getInstance().getOutputVolume());
|
||||
if (state != AL_PLAYING)
|
||||
{
|
||||
alSourcePlay(alSource);
|
||||
//qDebug() << "Starting audio source " << (int)alSource;
|
||||
}
|
||||
}
|
||||
|
||||
VideoSource *CoreAV::getVideoSourceFromCall(int friendNum)
|
||||
{
|
||||
assert(calls.contains(friendNum));
|
||||
|
@ -460,7 +458,7 @@ void CoreAV::callCallback(ToxAV*, uint32_t friendNum, bool, bool video, void *_s
|
|||
{
|
||||
qWarning() << "RECEIVED CALL";
|
||||
CoreAV* self = static_cast<CoreAV*>(_self);
|
||||
calls.insert(friendNum, {friendNum, video, *self});
|
||||
calls.insert({friendNum, video, *self});
|
||||
emit reinterpret_cast<CoreAV*>(self)->avInvite(friendNum, video);
|
||||
}
|
||||
|
||||
|
@ -506,6 +504,7 @@ void CoreAV::videoBitrateCallback(ToxAV *toxAV, uint32_t friendNum, bool stable,
|
|||
void CoreAV::audioFrameCallback(ToxAV *toxAV, uint32_t friendNum, const int16_t *pcm, size_t sampleCount, uint8_t channels, uint32_t samplingRate, void *self)
|
||||
{
|
||||
qWarning() << "AUDIO FRAME";
|
||||
Audio::playAudioBuffer(calls[friendNum].alSource, pcm, sampleCount, channels, samplingRate);
|
||||
}
|
||||
|
||||
void CoreAV::videoFrameCallback(ToxAV *toxAV, uint32_t friendNum, uint16_t w, uint16_t h, const uint8_t *y, const uint8_t *u, const uint8_t *v, int32_t ystride, int32_t ustride, int32_t vstride, void *self)
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include <AL/alc.h>
|
||||
#endif
|
||||
|
||||
#include "src/core/indexedlist.h"
|
||||
|
||||
#ifdef QTOX_FILTER_AUDIO
|
||||
class AudioFilterer;
|
||||
#endif
|
||||
|
@ -51,9 +53,15 @@ struct ToxCall
|
|||
{
|
||||
ToxCall() = default;
|
||||
ToxCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av);
|
||||
ToxCall(const ToxCall& other) = delete;
|
||||
ToxCall(ToxCall&& other) noexcept;
|
||||
~ToxCall();
|
||||
|
||||
QTimer *sendAudioTimer;
|
||||
inline operator int() {return friendNum;}
|
||||
const ToxCall& operator=(const ToxCall& other) = delete;
|
||||
const ToxCall& operator=(ToxCall&& other) noexcept;
|
||||
|
||||
QTimer* sendAudioTimer;
|
||||
uint32_t friendNum;
|
||||
bool muteMic;
|
||||
bool muteVol;
|
||||
|
@ -153,7 +161,7 @@ private:
|
|||
|
||||
private:
|
||||
ToxAV* toxav;
|
||||
static QHash<uint32_t, ToxCall> calls;
|
||||
static IndexedList<ToxCall> calls;
|
||||
static QHash<int, ToxGroupCall> groupCalls; // Maps group IDs to ToxGroupCalls
|
||||
|
||||
friend class Audio;
|
||||
|
|
45
src/core/indexedlist.h
Normal file
45
src/core/indexedlist.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef INDEXEDLIST_H
|
||||
#define INDEXEDLIST_H
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
/// More or less a hashmap, indexed by the noexcept move-only value type's operator int
|
||||
/// Really nice to store our ToxCall objects.
|
||||
template <typename T>
|
||||
class IndexedList
|
||||
{
|
||||
public:
|
||||
explicit IndexedList() = default;
|
||||
|
||||
// Qt
|
||||
inline bool isEmpty() { return v.empty(); }
|
||||
bool contains(int i) { return std::find_if(begin(), end(), [i](T& t){return (int)t == i;}) != end(); }
|
||||
void remove(int i) { v.erase(std::remove_if(begin(), end(), [i](T& t){return (int)t == i;})); }
|
||||
T& operator[](int i)
|
||||
{
|
||||
iterator it = std::find_if(begin(), end(), [i](T& t){return (int)t == i;});
|
||||
if (it == end())
|
||||
it = insert({});
|
||||
return *it;
|
||||
}
|
||||
|
||||
// STL
|
||||
using iterator = typename std::vector<T>::iterator;
|
||||
using const_iterator = typename std::vector<T>::const_iterator;
|
||||
|
||||
inline iterator begin() { return v.begin(); }
|
||||
inline const_iterator begin() const { return v.begin(); }
|
||||
inline const_iterator cbegin() const { return v.cbegin(); }
|
||||
inline iterator end() { return v.end(); }
|
||||
inline const_iterator end() const { return v.end(); }
|
||||
inline const_iterator cend() const { return v.cend(); }
|
||||
inline iterator erase(iterator pos) { return v.erase(pos); }
|
||||
inline iterator erase(iterator first, iterator last) { return v.erase(first, last); }
|
||||
inline iterator insert(T&& value) { v.push_back(std::move(value)); return v.end(); }
|
||||
|
||||
private:
|
||||
std::vector<T> v;
|
||||
};
|
||||
|
||||
#endif // INDEXEDLIST_H
|
Loading…
Reference in New Issue
Block a user