mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
the big code cleanup
* Get rid of static vars and methods and move mutexes to right places. * Use static wrappers for the moment to retain compatibility.
This commit is contained in:
parent
2a2cba3cf2
commit
1c205b7c16
|
@ -31,63 +31,78 @@
|
|||
#include "src/persistence/settings.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QThread>
|
||||
#include <QMutexLocker>
|
||||
#include <QTimer>
|
||||
#include <QThread>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
std::atomic<int> Audio::userCount{0};
|
||||
Audio* Audio::instance{nullptr};
|
||||
QThread* Audio::audioThread{nullptr};
|
||||
QMutex* Audio::audioInLock{nullptr};
|
||||
QMutex* Audio::audioOutLock{nullptr};
|
||||
ALCdevice* Audio::alInDev{nullptr};
|
||||
ALCdevice* Audio::alOutDev{nullptr};
|
||||
ALCcontext* Audio::alContext{nullptr};
|
||||
ALuint Audio::alMainSource{0};
|
||||
float Audio::outputVolume{1.0};
|
||||
float Audio::inputVolume{1.0};
|
||||
QTimer* Audio::timer{nullptr};
|
||||
|
||||
Audio& Audio::getInstance()
|
||||
{
|
||||
if (!instance)
|
||||
{
|
||||
instance = new Audio();
|
||||
audioThread = new QThread(instance);
|
||||
audioThread->setObjectName("qTox Audio");
|
||||
audioThread->start();
|
||||
audioInLock = new QMutex(QMutex::Recursive);
|
||||
audioOutLock = new QMutex(QMutex::Recursive);
|
||||
instance->moveToThread(audioThread);
|
||||
timer = new QTimer(instance);
|
||||
timer->moveToThread(audioThread);
|
||||
timer->setSingleShot(true);
|
||||
instance->connect(timer, &QTimer::timeout, instance, &Audio::closeOutput);
|
||||
instance->startAudioThread();
|
||||
}
|
||||
return *instance;
|
||||
}
|
||||
|
||||
Audio::Audio()
|
||||
: audioThread(new QThread())
|
||||
, audioInLock(QMutex::Recursive)
|
||||
, audioOutLock(QMutex::Recursive)
|
||||
, userCount(0)
|
||||
, alOutDev(nullptr)
|
||||
, alInDev(nullptr)
|
||||
, outputVolume(1.0)
|
||||
, inputVolume(1.0)
|
||||
, alMainSource(0)
|
||||
, alContext(nullptr)
|
||||
, timer(new QTimer(this))
|
||||
{
|
||||
timer->setSingleShot(true);
|
||||
connect(timer, &QTimer::timeout, this, &Audio::closeOutput);
|
||||
|
||||
audioThread->setObjectName("qTox Audio");
|
||||
connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater);
|
||||
}
|
||||
|
||||
Audio::~Audio()
|
||||
{
|
||||
audioThread->exit(0);
|
||||
audioThread->exit();
|
||||
audioThread->wait();
|
||||
if (audioThread->isRunning())
|
||||
audioThread->terminate();
|
||||
}
|
||||
|
||||
delete audioThread;
|
||||
delete audioInLock;
|
||||
delete audioOutLock;
|
||||
void Audio::startAudioThread()
|
||||
{
|
||||
if (!audioThread->isRunning())
|
||||
audioThread->start();
|
||||
|
||||
moveToThread(audioThread);
|
||||
}
|
||||
|
||||
float Audio::getOutputVolume()
|
||||
{
|
||||
return getInstance().GetOutputVolume();
|
||||
}
|
||||
|
||||
qreal Audio::GetOutputVolume()
|
||||
{
|
||||
QMutexLocker locker(&audioOutLock);
|
||||
return outputVolume;
|
||||
}
|
||||
|
||||
void Audio::setOutputVolume(float volume)
|
||||
{
|
||||
getInstance().SetOutputVolume(volume);
|
||||
}
|
||||
|
||||
void Audio::SetOutputVolume(qreal volume)
|
||||
{
|
||||
QMutexLocker locker(&audioOutLock);
|
||||
outputVolume = volume;
|
||||
alSourcef(alMainSource, AL_GAIN, outputVolume);
|
||||
|
||||
|
@ -109,21 +124,30 @@ void Audio::setOutputVolume(float volume)
|
|||
|
||||
void Audio::setInputVolume(float volume)
|
||||
{
|
||||
getInstance().SetInputVolume(volume);
|
||||
}
|
||||
|
||||
void Audio::SetInputVolume(qreal volume)
|
||||
{
|
||||
QMutexLocker locker(&audioInLock);
|
||||
inputVolume = volume;
|
||||
}
|
||||
|
||||
void Audio::suscribeInput()
|
||||
{
|
||||
Audio& inst = Audio::getInstance();
|
||||
inst.SubscribeInput();
|
||||
}
|
||||
|
||||
QMutexLocker lock(audioInLock);
|
||||
QMutexLocker locker(audioOutLock);
|
||||
void Audio::SubscribeInput()
|
||||
{
|
||||
assert(userCount >= 0);
|
||||
|
||||
qDebug() << "subscribing input";
|
||||
|
||||
if (!userCount++)
|
||||
{
|
||||
openInput(Settings::getInstance().getInDev());
|
||||
OpenInput(Settings::getInstance().getInDev());
|
||||
|
||||
#if (!FIX_SND_PCM_PREPARE_BUG)
|
||||
if (alInDev)
|
||||
|
@ -134,16 +158,20 @@ void Audio::suscribeInput()
|
|||
#endif
|
||||
}
|
||||
|
||||
QTimer::singleShot(1, []()
|
||||
QTimer::singleShot(1, [=]()
|
||||
{
|
||||
Audio::openOutput(Settings::getInstance().getOutDev());
|
||||
OpenOutput(Settings::getInstance().getOutDev());
|
||||
});
|
||||
}
|
||||
|
||||
void Audio::unsuscribeInput()
|
||||
{
|
||||
QMutexLocker lock(audioInLock);
|
||||
QMutexLocker locker(audioOutLock);
|
||||
Audio& inst = Audio::getInstance();
|
||||
inst.UnSubscribeInput();
|
||||
}
|
||||
|
||||
void Audio::UnSubscribeInput()
|
||||
{
|
||||
assert(userCount > 0);
|
||||
|
||||
qDebug() << "unsubscribing input" << userCount;
|
||||
|
@ -163,7 +191,12 @@ void Audio::unsuscribeInput()
|
|||
|
||||
void Audio::openInput(const QString& inDevDescr)
|
||||
{
|
||||
QMutexLocker lock(audioInLock);
|
||||
getInstance().OpenInput(inDevDescr);
|
||||
}
|
||||
|
||||
void Audio::OpenInput(const QString& inDevDescr)
|
||||
{
|
||||
QMutexLocker lock(&audioInLock);
|
||||
auto* tmp = alInDev;
|
||||
alInDev = nullptr;
|
||||
if (tmp)
|
||||
|
@ -198,12 +231,16 @@ void Audio::openInput(const QString& inDevDescr)
|
|||
alcCaptureStart(alInDev);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool Audio::openOutput(const QString& outDevDescr)
|
||||
{
|
||||
QMutexLocker lock(audioOutLock);
|
||||
return getInstance().OpenOutput(outDevDescr);
|
||||
}
|
||||
|
||||
bool Audio::OpenOutput(const QString &outDevDescr)
|
||||
{
|
||||
QMutexLocker lock(&audioOutLock);
|
||||
auto* tmp = alOutDev;
|
||||
alOutDev = nullptr;
|
||||
if (outDevDescr.isEmpty())
|
||||
|
@ -224,7 +261,7 @@ bool Audio::openOutput(const QString& outDevDescr)
|
|||
if (tmp)
|
||||
alcCloseDevice(tmp);
|
||||
|
||||
alContext=alcCreateContext(alOutDev,nullptr);
|
||||
alContext = alcCreateContext(alOutDev,nullptr);
|
||||
if (!alcMakeContextCurrent(alContext))
|
||||
{
|
||||
qWarning() << "Cannot create output audio context";
|
||||
|
@ -247,9 +284,14 @@ bool Audio::openOutput(const QString& outDevDescr)
|
|||
}
|
||||
|
||||
void Audio::closeInput()
|
||||
{
|
||||
getInstance().CloseInput();
|
||||
}
|
||||
|
||||
void Audio::CloseInput()
|
||||
{
|
||||
qDebug() << "Closing input";
|
||||
QMutexLocker lock(audioInLock);
|
||||
QMutexLocker locker(&audioInLock);
|
||||
if (alInDev)
|
||||
{
|
||||
if (alcCaptureCloseDevice(alInDev) == ALC_TRUE)
|
||||
|
@ -265,9 +307,14 @@ void Audio::closeInput()
|
|||
}
|
||||
|
||||
void Audio::closeOutput()
|
||||
{
|
||||
getInstance().CloseOutput();
|
||||
}
|
||||
|
||||
void Audio::CloseOutput()
|
||||
{
|
||||
qDebug() << "Closing output";
|
||||
QMutexLocker lock(audioOutLock);
|
||||
QMutexLocker locker(&audioOutLock);
|
||||
|
||||
if (userCount > 0)
|
||||
return;
|
||||
|
@ -289,7 +336,12 @@ void Audio::closeOutput()
|
|||
|
||||
void Audio::playMono16Sound(const QByteArray& data)
|
||||
{
|
||||
QMutexLocker lock(audioOutLock);
|
||||
getInstance().PlayMono16Sound(data);
|
||||
}
|
||||
|
||||
void Audio::PlayMono16Sound(const QByteArray& data)
|
||||
{
|
||||
QMutexLocker lock(&audioOutLock);
|
||||
|
||||
if (!alOutDev)
|
||||
{
|
||||
|
@ -336,10 +388,16 @@ void Audio::playGroupAudioQueued(Tox*,int group, int peer, const int16_t* data,
|
|||
|
||||
void Audio::playGroupAudio(int group, int peer, const int16_t* data,
|
||||
unsigned samples, uint8_t channels, unsigned sample_rate)
|
||||
{
|
||||
getInstance().PlayGroupAudio(group, peer, data, samples, channels, sample_rate);
|
||||
}
|
||||
|
||||
void Audio::PlayGroupAudio(int group, int peer, const int16_t* data,
|
||||
unsigned samples, uint8_t channels, unsigned sample_rate)
|
||||
{
|
||||
assert(QThread::currentThread() == audioThread);
|
||||
|
||||
QMutexLocker lock(audioOutLock);
|
||||
QMutexLocker lock(&audioOutLock);
|
||||
|
||||
ToxGroupCall& call = Core::groupCalls[group];
|
||||
|
||||
|
@ -366,7 +424,7 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u
|
|||
{
|
||||
assert(channels == 1 || channels == 2);
|
||||
|
||||
QMutexLocker lock(audioOutLock);
|
||||
QMutexLocker lock(&audioOutLock);
|
||||
|
||||
ALuint bufid;
|
||||
ALint processed = 0, queued = 16;
|
||||
|
@ -404,17 +462,34 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u
|
|||
|
||||
bool Audio::isInputReady()
|
||||
{
|
||||
return getInstance().IsInputReady();
|
||||
}
|
||||
|
||||
bool Audio::IsInputReady()
|
||||
{
|
||||
QMutexLocker locker(&audioInLock);
|
||||
return (alInDev && userCount);
|
||||
}
|
||||
|
||||
bool Audio::isOutputClosed()
|
||||
{
|
||||
return getInstance().IsOutputClosed();
|
||||
}
|
||||
|
||||
bool Audio::IsOutputClosed()
|
||||
{
|
||||
QMutexLocker locker(&audioOutLock);
|
||||
return (alOutDev);
|
||||
}
|
||||
|
||||
bool Audio::tryCaptureSamples(uint8_t* buf, int framesize)
|
||||
{
|
||||
QMutexLocker lock(audioInLock);
|
||||
return getInstance().TryCaptureSamples(buf, framesize);
|
||||
}
|
||||
|
||||
bool Audio::TryCaptureSamples(uint8_t* buf, int framesize)
|
||||
{
|
||||
QMutexLocker lock(&audioInLock);
|
||||
|
||||
ALint samples=0;
|
||||
alcGetIntegerv(Audio::alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
|
||||
|
@ -445,7 +520,12 @@ bool Audio::tryCaptureSamples(uint8_t* buf, int framesize)
|
|||
|
||||
void Audio::pauseOutput()
|
||||
{
|
||||
QMutexLocker lock(audioOutLock);
|
||||
getInstance().PauseOutput();
|
||||
}
|
||||
|
||||
void Audio::PauseOutput()
|
||||
{
|
||||
QMutexLocker lock(&audioOutLock);
|
||||
|
||||
qDebug() << "Pause";
|
||||
if (userCount == 0)
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
#include <QMutexLocker>
|
||||
#include <atomic>
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
|
@ -48,29 +49,47 @@ class Audio : public QObject
|
|||
public:
|
||||
static Audio& getInstance(); ///< Returns the singleton's instance. Will construct on first call.
|
||||
|
||||
public:
|
||||
void startAudioThread();
|
||||
|
||||
static float getOutputVolume(); ///< Returns the current output volume, between 0 and 1
|
||||
qreal GetOutputVolume();
|
||||
static void setOutputVolume(float volume); ///< The volume must be between 0 and 1
|
||||
void SetOutputVolume(qreal volume);
|
||||
|
||||
static void setInputVolume(float volume); ///< The volume must be between 0 and 2
|
||||
void SetInputVolume(qreal volume);
|
||||
|
||||
static void suscribeInput(); ///< Call when you need to capture sound from the open input device.
|
||||
void SubscribeInput();
|
||||
static void unsuscribeInput(); ///< Call once you don't need to capture on the open input device anymore.
|
||||
void UnSubscribeInput();
|
||||
|
||||
static void openInput(const QString& inDevDescr); ///< Open an input device, use before suscribing
|
||||
void OpenInput(const QString& inDevDescr);
|
||||
static bool openOutput(const QString& outDevDescr); ///< Open an output device
|
||||
|
||||
static void closeInput(); ///< Close an input device, please don't use unless everyone's unsuscribed
|
||||
bool OpenOutput(const QString& outDevDescr);
|
||||
static void closeInput();
|
||||
void CloseInput();
|
||||
static void closeOutput(); ///< Close an output device
|
||||
void CloseOutput();
|
||||
|
||||
static bool isInputReady(); ///< Returns true if the input device is open and suscribed to
|
||||
bool IsInputReady();
|
||||
static bool isOutputClosed(); ///< Returns true if the output device is open
|
||||
bool IsOutputClosed();
|
||||
|
||||
static void playMono16Sound(const QByteArray& data); ///< Play a 44100Hz mono 16bit PCM sound
|
||||
void PlayMono16Sound(const QByteArray& data);
|
||||
static bool tryCaptureSamples(uint8_t* buf, int framesize); ///< Does nothing and return false on failure
|
||||
bool TryCaptureSamples(uint8_t* buf, int framesize);
|
||||
|
||||
/// May be called from any thread, will always queue a call to playGroupAudio
|
||||
/// The first and last argument are ignored, but allow direct compatibility with toxcore
|
||||
static void playGroupAudioQueued(Tox*, int group, int peer, const int16_t* data,
|
||||
unsigned samples, uint8_t channels, unsigned sample_rate, void*);
|
||||
void PlayGroupAudio(int group, int peer, const int16_t* data,
|
||||
unsigned samples, uint8_t channels, unsigned sample_rate);
|
||||
|
||||
#ifdef QTOX_FILTER_AUDIO
|
||||
static void getEchoesToFilter(AudioFilterer* filter, int framesize);
|
||||
|
@ -82,26 +101,31 @@ public slots:
|
|||
void playGroupAudio(int group, int peer, const int16_t* data,
|
||||
unsigned samples, uint8_t channels, unsigned sample_rate);
|
||||
static void pauseOutput();
|
||||
void PauseOutput();
|
||||
|
||||
signals:
|
||||
void groupAudioPlayed(int group, int peer, unsigned short volume);
|
||||
|
||||
private:
|
||||
explicit Audio()=default;
|
||||
Audio();
|
||||
~Audio();
|
||||
static void playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate);
|
||||
|
||||
void playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate);
|
||||
|
||||
private:
|
||||
static Audio* instance;
|
||||
static std::atomic<int> userCount;
|
||||
static ALCdevice* alOutDev, *alInDev;
|
||||
static QMutex* audioInLock, *audioOutLock;
|
||||
static float outputVolume;
|
||||
static float inputVolume;
|
||||
static ALuint alMainSource;
|
||||
static QThread* audioThread;
|
||||
static ALCcontext* alContext;
|
||||
static QTimer* timer;
|
||||
|
||||
QThread* audioThread;
|
||||
QMutex audioInLock;
|
||||
QMutex audioOutLock;
|
||||
std::atomic<int> userCount;
|
||||
ALCdevice* alOutDev;
|
||||
ALCdevice* alInDev;
|
||||
qreal outputVolume;
|
||||
qreal inputVolume;
|
||||
ALuint alMainSource;
|
||||
ALCcontext* alContext;
|
||||
QTimer* timer;
|
||||
};
|
||||
|
||||
#endif // AUDIO_H
|
||||
|
|
Loading…
Reference in New Issue
Block a user