1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

refactor(audio): Remove Audio singleton

This commit finally removes the Audio singleton and allocates the audio
backend in main.cpp.
This commit is contained in:
sudden6 2019-05-18 19:08:58 +02:00
parent 17048c9cc4
commit 22362d2940
No known key found for this signature in database
GPG Key ID: 279509B499E032B9
23 changed files with 325 additions and 244 deletions

View File

@ -243,6 +243,7 @@ set(${PROJECT_NAME}_SOURCES
src/audio/backend/openal.cpp
src/audio/backend/openal.h
src/audio/iaudiosettings.h
src/audio/iaudiocontrol.h
src/audio/iaudiosink.h
src/audio/iaudiosource.h
src/chatlog/chatlinecontent.cpp

View File

@ -17,109 +17,30 @@
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#include "audio.h"
#include <memory>
#include "src/audio/audio.h"
#include "src/audio/iaudiosettings.h"
#include "src/audio/backend/openal.h"
#ifdef USE_FILTERAUDIO
#include "src/audio/backend/openal2.h"
#endif
#include "src/persistence/settings.h"
/**
* @class Audio
*
* @var Audio::AUDIO_SAMPLE_RATE
* @brief The next best Opus would take is 24k
*
* @var Audio::AUDIO_FRAME_DURATION
* @brief In milliseconds
*
* @var Audio::AUDIO_FRAME_SAMPLE_COUNT
* @brief Frame sample count
*
* @fn qreal Audio::outputVolume() const
* @brief Returns the current output volume (between 0 and 1)
*
* @fn void Audio::setOutputVolume(qreal volume)
* @brief Set the master output volume.
*
* @param[in] volume the master volume (between 0 and 1)
*
* @fn qreal Audio::minInputGain() const
* @brief The minimum gain value for an input device.
*
* @return minimum gain value in dB
*
* @fn void Audio::setMinInputGain(qreal dB)
* @brief Set the minimum allowed gain value in dB.
*
* @note Default is -30dB; usually you don't need to alter this value;
*
* @fn qreal Audio::maxInputGain() const
* @brief The maximum gain value for an input device.
*
* @return maximum gain value in dB
*
* @fn void Audio::setMaxInputGain(qreal dB)
* @brief Set the maximum allowed gain value in dB.
*
* @note Default is 30dB; usually you don't need to alter this value.
*
* @fn bool Audio::isOutputReady() const
* @brief check if the output is ready to play audio
*
* @return true if the output device is open, false otherwise
*
* @fn QStringList Audio::outDeviceNames()
* @brief Get the names of available output devices
*
* @return list of output devices
*
* @fn QStringList Audio::inDeviceNames()
* @brief Get the names of available input devices
*
* @return list of input devices
*
* @fn qreal Audio::inputGain() const
* @brief get the current input gain
*
* @return current input gain in dB
*
* @fn void Audio::setInputGain(qreal dB)
* @brief set the input gain
*
* @fn void Audio::getInputThreshold()
* @brief get the current input threshold
*
* @return current input threshold percentage
*
* @fn void Audio::setInputThreshold(qreal percent)
* @brief set the input threshold
*
* @param[in] percent the new input threshold percentage
* @brief Select the audio backend
* @param settings Audio settings to use
* @return Audio backend selection based on settings
*/
/**
* @brief Returns the singleton instance.
*/
Audio& Audio::getInstance()
std::unique_ptr<IAudioControl> Audio::makeAudio(IAudioSettings& settings)
{
// TODO: replace backend selection by inversion of control
#ifdef USE_FILTERAUDIO
static bool initialized = false;
static bool Backend2 = false;
if (!initialized) {
Backend2 = Settings::getInstance().getEnableBackend2();
initialized = true;
}
const bool Backend2 = settings.getEnableBackend2();
if (Backend2) {
static OpenAL2 instance;
return instance;
return std::unique_ptr<IAudioControl>(new OpenAL2());
} else
#endif
{
static OpenAL instance;
return instance;
return std::unique_ptr<IAudioControl>(new OpenAL());
}
}

View File

@ -21,57 +21,14 @@
#ifndef AUDIO_H
#define AUDIO_H
#include <QObject>
#include <memory>
class IAudioSink;
class IAudioSource;
class Audio : public QObject
class IAudioControl;
class IAudioSettings;
class Audio
{
Q_OBJECT
public:
static Audio& getInstance();
virtual qreal outputVolume() const = 0;
virtual void setOutputVolume(qreal volume) = 0;
virtual qreal maxOutputVolume() const = 0;
virtual qreal minOutputVolume() const = 0;
virtual qreal minInputGain() const = 0;
virtual void setMinInputGain(qreal dB) = 0;
virtual qreal maxInputGain() const = 0;
virtual void setMaxInputGain(qreal dB) = 0;
virtual qreal inputGain() const = 0;
virtual void setInputGain(qreal dB) = 0;
virtual qreal minInputThreshold() const = 0;
virtual qreal maxInputThreshold() const = 0;
virtual qreal getInputThreshold() const = 0;
virtual void setInputThreshold(qreal percent) = 0;
virtual void reinitInput(const QString& inDevDesc) = 0;
virtual bool reinitOutput(const QString& outDevDesc) = 0;
virtual bool isOutputReady() const = 0;
virtual QStringList outDeviceNames() = 0;
virtual QStringList inDeviceNames() = 0;
virtual std::unique_ptr<IAudioSink> makeSink() = 0;
virtual std::unique_ptr<IAudioSource> makeSource() = 0;
protected:
// Public default audio settings
// Samplerate for Tox calls and sounds
static constexpr uint32_t AUDIO_SAMPLE_RATE = 48000;
static constexpr uint32_t AUDIO_FRAME_DURATION = 20;
static constexpr uint32_t AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL =
AUDIO_FRAME_DURATION * AUDIO_SAMPLE_RATE / 1000;
uint32_t AUDIO_FRAME_SAMPLE_COUNT_TOTAL = 0;
static std::unique_ptr<IAudioControl> makeAudio(IAudioSettings& settings);
};
#endif // AUDIO_H

View File

@ -21,7 +21,7 @@
#ifndef OPENAL_H
#define OPENAL_H
#include "src/audio/audio.h"
#include "src/audio/iaudiocontrol.h"
#include "src/audio/backend/alsink.h"
#include "src/audio/backend/alsource.h"
@ -45,7 +45,7 @@
#include <AL/alext.h>
#endif
class OpenAL : public Audio
class OpenAL : public IAudioControl
{
Q_OBJECT

View File

@ -159,7 +159,7 @@ bool OpenAL2::initOutputEchoCancel()
ALC_FORMAT_TYPE_SOFT,
ALC_SHORT_SOFT,
ALC_FREQUENCY,
Audio::AUDIO_SAMPLE_RATE,
IAudioControl::AUDIO_SAMPLE_RATE,
0}; // End of List
alProxyDev = alcLoopbackOpenDeviceSOFT(nullptr);

View File

@ -21,7 +21,7 @@
#ifndef OPENAL2_H
#define OPENAL2_H
#include "src/audio/audio.h"
#include "src/audio/iaudiocontrol.h"
#include "src/audio/backend/openal.h"
#include <atomic>

131
src/audio/iaudiocontrol.h Normal file
View File

@ -0,0 +1,131 @@
#ifndef IAUDIOCONTROL_H
#define IAUDIOCONTROL_H
#include <QObject>
#include <QStringList>
#include <memory>
/**
* @class IAudioControl
*
* @var IAudioControl::AUDIO_SAMPLE_RATE
* @brief The next best Opus would take is 24k
*
* @var IAudioControl::AUDIO_FRAME_DURATION
* @brief In milliseconds
*
* @var IAudioControl::AUDIO_FRAME_SAMPLE_COUNT
* @brief Frame sample count
*
* @fn qreal IAudioControl::outputVolume() const
* @brief Returns the current output volume (between 0 and 1)
*
* @fn void IAudioControl::setOutputVolume(qreal volume)
* @brief Set the master output volume.
*
* @param[in] volume the master volume (between 0 and 1)
*
* @fn qreal IAudioControl::minInputGain() const
* @brief The minimum gain value for an input device.
*
* @return minimum gain value in dB
*
* @fn void IAudioControl::setMinInputGain(qreal dB)
* @brief Set the minimum allowed gain value in dB.
*
* @note Default is -30dB; usually you don't need to alter this value;
*
* @fn qreal IAudioControl::maxInputGain() const
* @brief The maximum gain value for an input device.
*
* @return maximum gain value in dB
*
* @fn void IAudioControl::setMaxInputGain(qreal dB)
* @brief Set the maximum allowed gain value in dB.
*
* @note Default is 30dB; usually you don't need to alter this value.
*
* @fn bool IAudioControl::isOutputReady() const
* @brief check if the output is ready to play audio
*
* @return true if the output device is open, false otherwise
*
* @fn QStringList IAudioControl::outDeviceNames()
* @brief Get the names of available output devices
*
* @return list of output devices
*
* @fn QStringList IAudioControl::inDeviceNames()
* @brief Get the names of available input devices
*
* @return list of input devices
*
* @fn qreal IAudioControl::inputGain() const
* @brief get the current input gain
*
* @return current input gain in dB
*
* @fn void IAudioControl::setInputGain(qreal dB)
* @brief set the input gain
*
* @fn void IAudioControl::getInputThreshold()
* @brief get the current input threshold
*
* @return current input threshold percentage
*
* @fn void IAudioControl::setInputThreshold(qreal percent)
* @brief set the input threshold
*
* @param[in] percent the new input threshold percentage
*/
class IAudioSink;
class IAudioSource;
class IAudioControl : public QObject
{
Q_OBJECT
public:
virtual qreal outputVolume() const = 0;
virtual void setOutputVolume(qreal volume) = 0;
virtual qreal maxOutputVolume() const = 0;
virtual qreal minOutputVolume() const = 0;
virtual qreal minInputGain() const = 0;
virtual void setMinInputGain(qreal dB) = 0;
virtual qreal maxInputGain() const = 0;
virtual void setMaxInputGain(qreal dB) = 0;
virtual qreal inputGain() const = 0;
virtual void setInputGain(qreal dB) = 0;
virtual qreal minInputThreshold() const = 0;
virtual qreal maxInputThreshold() const = 0;
virtual qreal getInputThreshold() const = 0;
virtual void setInputThreshold(qreal percent) = 0;
virtual void reinitInput(const QString& inDevDesc) = 0;
virtual bool reinitOutput(const QString& outDevDesc) = 0;
virtual bool isOutputReady() const = 0;
virtual QStringList outDeviceNames() = 0;
virtual QStringList inDeviceNames() = 0;
virtual std::unique_ptr<IAudioSink> makeSink() = 0;
virtual std::unique_ptr<IAudioSource> makeSource() = 0;
protected:
// Public default audio settings
// Samplerate for Tox calls and sounds
static constexpr uint32_t AUDIO_SAMPLE_RATE = 48000;
static constexpr uint32_t AUDIO_FRAME_DURATION = 20;
static constexpr uint32_t AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL =
AUDIO_FRAME_DURATION * AUDIO_SAMPLE_RATE / 1000;
uint32_t AUDIO_FRAME_SAMPLE_COUNT_TOTAL = 0;
};
#endif // IAUDIOCONTROL_H

View File

@ -281,6 +281,7 @@ ToxCorePtr Core::makeToxCore(const QByteArray& savedata, const ICoreSettings* co
assert(core->tox != nullptr);
// toxcore is successfully created, create toxav
// TODO(sudden6): don't create CoreAv here, Core should be usable without CoreAV
core->av = CoreAV::makeCoreAV(core->tox.get());
if (!core->av) {
qCritical() << "Toxav failed to start";

View File

@ -40,6 +40,7 @@
class CoreAV;
class CoreFile;
class IAudioControl;
class ICoreSettings;
class GroupInvite;
class Profile;

View File

@ -81,7 +81,8 @@ std::map<uint32_t, CoreAV::ToxFriendCallPtr> CoreAV::calls;
std::map<int, CoreAV::ToxGroupCallPtr> CoreAV::groupCalls;
CoreAV::CoreAV(std::unique_ptr<ToxAV, ToxAVDeleter> toxav)
: toxav{std::move(toxav)}
: audio{nullptr}
, toxav{std::move(toxav)}
, coreavThread{new QThread{this}}
, iterateTimer{new QTimer{this}}
, threadSwitchLock{false}
@ -102,7 +103,8 @@ CoreAV::CoreAV(std::unique_ptr<ToxAV, ToxAVDeleter> toxav)
coreavThread->start();
}
void CoreAV::connectCallbacks(ToxAV& toxav) {
void CoreAV::connectCallbacks(ToxAV& toxav)
{
toxav_callback_call(&toxav, CoreAV::callCallback, this);
toxav_callback_call_state(&toxav, CoreAV::stateCallback, this);
toxav_callback_audio_bit_rate(&toxav, CoreAV::audioBitrateCallback, this);
@ -139,6 +141,27 @@ CoreAV::CoreAVPtr CoreAV::makeCoreAV(Tox* core)
return CoreAVPtr{new CoreAV{std::move(toxav)}};
}
/**
* @brief Set the audio backend
* @param audio The audio backend to use
* @note This must be called before starting CoreAV and audio must outlive CoreAV
*/
void CoreAV::setAudio(IAudioControl& newAudio)
{
audio.exchange(&newAudio);
}
/**
* @brief Get the audio backend used
* @return Pointer to the audio backend
* @note This is needed only for the case CoreAV needs to restart and the restarting class doesn't
* have access to the audio backend and wants to keep it the same.
*/
IAudioControl* CoreAV::getAudio()
{
return audio;
}
CoreAV::~CoreAV()
{
for (const auto& call : calls) {
@ -253,7 +276,8 @@ bool CoreAV::answerCall(uint32_t friendNum, bool video)
TOXAV_ERR_ANSWER err;
const uint32_t videoBitrate = video ? VIDEO_DEFAULT_BITRATE : 0;
if (toxav_answer(toxav.get(), friendNum, Settings::getInstance().getAudioBitrate(), videoBitrate, &err)) {
if (toxav_answer(toxav.get(), friendNum, Settings::getInstance().getAudioBitrate(),
videoBitrate, &err)) {
it->second->setActive(true);
return true;
} else {
@ -289,10 +313,13 @@ bool CoreAV::startCall(uint32_t friendNum, bool video)
}
uint32_t videoBitrate = video ? VIDEO_DEFAULT_BITRATE : 0;
if (!toxav_call(toxav.get(), friendNum, Settings::getInstance().getAudioBitrate(), videoBitrate, nullptr))
if (!toxav_call(toxav.get(), friendNum, Settings::getInstance().getAudioBitrate(), videoBitrate,
nullptr))
return false;
ToxFriendCallPtr call = ToxFriendCallPtr(new ToxFriendCall(friendNum, video, *this));
// Audio backend must be set before making a call
assert(audio != nullptr);
ToxFriendCallPtr call = ToxFriendCallPtr(new ToxFriendCall(friendNum, video, *this, *audio));
assert(call != nullptr);
auto ret = calls.emplace(friendNum, std::move(call));
ret.first->second->startTimeout(friendNum);
@ -420,8 +447,8 @@ void CoreAV::sendCallVideo(uint32_t callId, std::shared_ptr<VideoFrame> vframe)
TOXAV_ERR_SEND_FRAME err;
int retries = 0;
do {
if (!toxav_video_send_frame(toxav.get(), callId, frame.width, frame.height, frame.y, frame.u,
frame.v, &err)) {
if (!toxav_video_send_frame(toxav.get(), callId, frame.width, frame.height, frame.y,
frame.u, frame.v, &err)) {
if (err == TOXAV_ERR_SEND_FRAME_SYNC) {
++retries;
QThread::usleep(500);
@ -544,7 +571,9 @@ void CoreAV::joinGroupCall(int groupId)
{
qDebug() << QString("Joining group call %1").arg(groupId);
ToxGroupCallPtr groupcall = ToxGroupCallPtr(new ToxGroupCall{groupId, *this});
// Audio backend must be set before starting a call
assert(audio != nullptr);
ToxGroupCallPtr groupcall = ToxGroupCallPtr(new ToxGroupCall{groupId, *this, *audio});
assert(groupcall != nullptr);
auto ret = groupCalls.emplace(groupId, std::move(groupcall));
if (ret.second == false) {
@ -708,7 +737,9 @@ void CoreAV::callCallback(ToxAV* toxav, uint32_t friendNum, bool audio, bool vid
return;
}
ToxFriendCallPtr call = ToxFriendCallPtr(new ToxFriendCall{friendNum, video, *self});
// Audio backend must be set before receiving a call
assert(self->audio != nullptr);
ToxFriendCallPtr call = ToxFriendCallPtr(new ToxFriendCall{friendNum, video, *self, *self->audio});
assert(call != nullptr);
auto it = self->calls.emplace(friendNum, std::move(call));

View File

@ -29,6 +29,7 @@
class Friend;
class Group;
class IAudioControl;
class QThread;
class QTimer;
class CoreVideoSource;
@ -43,10 +44,12 @@ class CoreAV : public QObject
Q_OBJECT
public:
using CoreAVPtr = std::unique_ptr<CoreAV>;
static CoreAVPtr makeCoreAV(Tox* core);
void setAudio(IAudioControl& newAudio);
IAudioControl* getAudio();
~CoreAV();
bool anyActiveCalls() const;
@ -124,7 +127,8 @@ private:
static constexpr uint32_t VIDEO_DEFAULT_BITRATE = 2500;
private:
// atomic because potentially accessed by different threads
std::atomic<IAudioControl*> audio;
std::unique_ptr<ToxAV, ToxAVDeleter> toxav;
std::unique_ptr<QThread> coreavThread;
QTimer* iterateTimer = nullptr;
@ -133,8 +137,6 @@ private:
using ToxGroupCallPtr = std::unique_ptr<ToxGroupCall>;
static std::map<int, ToxGroupCallPtr> groupCalls;
std::atomic_flag threadSwitchLock;
friend class Audio;
};
#endif // COREAV_H

View File

@ -28,10 +28,11 @@
* @brief Keeps sources for users in group calls.
*/
ToxCall::ToxCall(bool VideoEnabled, CoreAV& av)
ToxCall::ToxCall(bool VideoEnabled, CoreAV& av, IAudioControl& audio)
: av{&av}
, audio(audio)
, videoEnabled{VideoEnabled}
, audioSource{Audio::getInstance().makeSource()}
, audioSource(audio.makeSource())
{}
ToxCall::~ToxCall()
@ -100,9 +101,9 @@ CoreVideoSource* ToxCall::getVideoSource() const
return videoSource;
}
ToxFriendCall::ToxFriendCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av)
: ToxCall(VideoEnabled, av)
, sink(Audio::getInstance().makeSink())
ToxFriendCall::ToxFriendCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av, IAudioControl& audio)
: ToxCall(VideoEnabled, av, audio)
, sink(audio.makeSink())
, friendId{FriendNum}
{
// TODO(sudden6): move this to audio source
@ -149,7 +150,7 @@ ToxFriendCall::~ToxFriendCall()
void ToxFriendCall::onAudioSourceInvalidated()
{
auto newSrc = Audio::getInstance().makeSource();
auto newSrc = audio.makeSource();
audioInConn =
QObject::connect(newSrc.get(), &IAudioSource::frameAvailable,
[this](const int16_t* pcm, size_t samples, uint8_t chans, uint32_t rate) {
@ -163,7 +164,7 @@ void ToxFriendCall::onAudioSourceInvalidated()
void ToxFriendCall::onAudioSinkInvalidated()
{
auto newSink = Audio::getInstance().makeSink();
auto newSink = audio.makeSink();
audioSinkInvalid = QObject::connect(newSink.get(), &IAudioSink::invalidated,
[this]() { this->onAudioSinkInvalidated(); });
@ -211,8 +212,8 @@ void ToxFriendCall::playAudioBuffer(const int16_t* data, int samples, unsigned c
}
}
ToxGroupCall::ToxGroupCall(int GroupNum, CoreAV& av)
: ToxCall(false, av)
ToxGroupCall::ToxGroupCall(int GroupNum, CoreAV& av, IAudioControl& audio)
: ToxCall(false, av, audio)
, groupId{GroupNum}
{
// register audio
@ -238,7 +239,7 @@ ToxGroupCall::~ToxGroupCall()
void ToxGroupCall::onAudioSourceInvalidated()
{
auto newSrc = Audio::getInstance().makeSource();
auto newSrc = audio.makeSource();
// TODO(sudden6): move this to audio source
audioInConn =
QObject::connect(audioSource.get(), &IAudioSource::frameAvailable,
@ -274,7 +275,6 @@ void ToxGroupCall::removePeer(ToxPk peerId)
void ToxGroupCall::addPeer(ToxPk peerId)
{
auto& audio = Audio::getInstance();
std::unique_ptr<IAudioSink> newSink = audio.makeSink();
peers.emplace(peerId, std::move(newSink));

View File

@ -1,6 +1,7 @@
#ifndef TOXCALL_H
#define TOXCALL_H
#include "src/audio/iaudiocontrol.h"
#include "src/audio/iaudiosink.h"
#include "src/audio/iaudiosource.h"
#include <src/core/toxpk.h>
@ -22,7 +23,7 @@ class ToxCall
{
protected:
ToxCall() = delete;
ToxCall(bool VideoEnabled, CoreAV& av);
ToxCall(bool VideoEnabled, CoreAV& av, IAudioControl& audio);
~ToxCall();
public:
@ -53,6 +54,7 @@ protected:
bool active{false};
CoreAV* av{nullptr};
// audio
IAudioControl& audio;
QMetaObject::Connection audioInConn;
bool muteMic{false};
bool muteVol{false};
@ -69,7 +71,7 @@ class ToxFriendCall : public ToxCall
{
public:
ToxFriendCall() = delete;
ToxFriendCall(uint32_t friendId, bool VideoEnabled, CoreAV& av);
ToxFriendCall(uint32_t friendId, bool VideoEnabled, CoreAV& av, IAudioControl& audio);
ToxFriendCall(ToxFriendCall&& other) = delete;
ToxFriendCall& operator=(ToxFriendCall&& other) = delete;
~ToxFriendCall();
@ -101,7 +103,7 @@ class ToxGroupCall : public ToxCall
{
public:
ToxGroupCall() = delete;
ToxGroupCall(int GroupNum, CoreAV& av);
ToxGroupCall(int GroupNum, CoreAV& av, IAudioControl& audio);
ToxGroupCall(ToxGroupCall&& other) = delete;
~ToxGroupCall();

View File

@ -17,11 +17,13 @@
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#include "persistence/settings.h"
#include "src/audio/audio.h"
#include "src/core/coreav.h"
#include "src/ipc.h"
#include "src/net/toxuri.h"
#include "src/nexus.h"
#include "src/persistence/profile.h"
#include "src/persistence/settings.h"
#include "src/persistence/toxsave.h"
#include "src/video/camerasource.h"
#include "src/widget/loginscreen.h"
@ -347,9 +349,17 @@ int main(int argc, char* argv[])
}
Nexus::getInstance().setProfile(profile);
Settings::getInstance().setCurrentProfile(profileName);
Settings& s = Settings::getInstance();
s.setCurrentProfile(profileName);
auto audio = Audio::makeAudio(s);
assert(audio != nullptr);
// TODO(sudden6): init CoreAV audio backend somewhere else so main doesn't depend on coreav.h
profile->getCore()->getAv()->setAudio(*audio);
Nexus& nexus = Nexus::getInstance();
// TODO(sudden6): remove once we get rid of Nexus
nexus.audio = audio.get();
nexus.start();
// Start to accept Inter-process communication

View File

@ -175,7 +175,7 @@ void Nexus::showMainGUI()
assert(profile);
// Create GUI
widget = Widget::getInstance();
widget = Widget::getInstance(audio);
// Start GUI
widget->init();

View File

@ -23,6 +23,8 @@
#include <QObject>
#include "src/audio/iaudiocontrol.h"
class Widget;
class Profile;
class Core;
@ -79,6 +81,9 @@ private:
QSignalMapper* windowMapper;
QActionGroup* windowActions = nullptr;
#endif
public:
// TODO(sudden6): hack to pass the audio instance
IAudioControl* audio = nullptr;
private:
explicit Nexus(QObject* parent = nullptr);

View File

@ -32,6 +32,7 @@
#include "profilelocker.h"
#include "settings.h"
#include "src/core/core.h"
#include "src/core/coreav.h"
#include "src/core/corefile.h"
#include "src/net/avatarbroadcaster.h"
#include "src/nexus.h"
@ -96,7 +97,8 @@ void Profile::initCore(const QByteArray& toxsave, ICoreSettings& s, bool isNewPr
Qt::ConnectionType::QueuedConnection);
}
Profile::Profile(QString name, const QString& password, bool isNewProfile, const QByteArray& toxsave, std::unique_ptr<ToxEncrypt> passkey)
Profile::Profile(QString name, const QString& password, bool isNewProfile,
const QByteArray& toxsave, std::unique_ptr<ToxEncrypt> passkey)
: name{name}
, passkey{std::move(passkey)}
, isRemoved{false}
@ -797,7 +799,10 @@ void Profile::restartCore()
if (saveToxSave(savedata)) {
qDebug() << "Restarting Core";
const bool isNewProfile{false};
IAudioControl* audioBak = core->getAv()->getAudio();
assert(audioBak != nullptr);
initCore(savedata, Settings::getInstance(), isNewProfile);
core->getAv()->setAudio(*audioBak);
core->start();
} else {
qCritical() << "Failed to save, not restarting core";

View File

@ -44,10 +44,10 @@
#define ALC_ALL_DEVICES_SPECIFIER ALC_DEVICE_SPECIFIER
#endif
AVForm::AVForm(Audio* audio, CoreAV* coreAV, CameraSource& camera, IAudioSettings* audioSettings,
IVideoSettings* videoSettings)
AVForm::AVForm(IAudioControl& audio, CoreAV* coreAV, CameraSource& camera,
IAudioSettings* audioSettings, IVideoSettings* videoSettings)
: GenericForm(QPixmap(":/img/settings/av.png"))
, audio{audio}
, audio(audio)
, coreAV{coreAV}
, audioSettings{audioSettings}
, videoSettings{videoSettings}
@ -78,8 +78,8 @@ AVForm::AVForm(Audio* audio, CoreAV* coreAV, CameraSource& camera, IAudioSetting
microphoneSlider->setToolTip(tr("Use slider to set the gain of your input device ranging"
" from %1dB to %2dB.")
.arg(audio->minInputGain())
.arg(audio->maxInputGain()));
.arg(audio.minInputGain())
.arg(audio.maxInputGain()));
microphoneSlider->setMaximum(totalSliderSteps);
microphoneSlider->setTickPosition(QSlider::TicksBothSides);
static const int numTicks = 4;
@ -87,14 +87,14 @@ AVForm::AVForm(Audio* audio, CoreAV* coreAV, CameraSource& camera, IAudioSetting
microphoneSlider->setTracking(false);
microphoneSlider->installEventFilter(this);
microphoneSlider->setValue(
getStepsFromValue(audio->inputGain(), audio->minInputGain(), audio->maxInputGain()));
getStepsFromValue(audio.inputGain(), audio.minInputGain(), audio.maxInputGain()));
audioThresholdSlider->setToolTip(tr("Use slider to set the activation volume for your"
" input device."));
audioThresholdSlider->setMaximum(totalSliderSteps);
audioThresholdSlider->setValue(getStepsFromValue(audioSettings->getAudioThreshold(),
audio->minInputThreshold(),
audio->maxInputThreshold()));
audio.minInputThreshold(),
audio.maxInputThreshold()));
audioThresholdSlider->setTracking(false);
audioThresholdSlider->installEventFilter(this);
@ -139,12 +139,12 @@ void AVForm::showEvent(QShowEvent* event)
getVideoDevices();
if (audioSrc == nullptr) {
audioSrc = audio->makeSource();
audioSrc = audio.makeSource();
connect(audioSrc.get(), &IAudioSource::volumeAvailable, this, &AVForm::setVolume);
}
if (audioSink == nullptr) {
audioSink = audio->makeSink();
audioSink = audio.makeSink();
}
GenericForm::showEvent(event);
@ -167,8 +167,7 @@ void AVForm::rescanDevices()
void AVForm::setVolume(float value)
{
volumeDisplay->setValue(
getStepsFromValue(value, audio->minOutputVolume(), audio->maxOutputVolume()));
volumeDisplay->setValue(getStepsFromValue(value, audio.minOutputVolume(), audio.maxOutputVolume()));
}
void AVForm::on_cbEnableBackend2_stateChanged()
@ -493,7 +492,7 @@ int AVForm::getModeSize(VideoMode mode)
void AVForm::getAudioInDevices()
{
QStringList deviceNames;
deviceNames << tr("Disabled") << audio->inDeviceNames();
deviceNames << tr("Disabled") << audio.inDeviceNames();
inDevCombobox->blockSignals(true);
inDevCombobox->clear();
@ -512,7 +511,7 @@ void AVForm::getAudioInDevices()
void AVForm::getAudioOutDevices()
{
QStringList deviceNames;
deviceNames << tr("Disabled") << audio->outDeviceNames();
deviceNames << tr("Disabled") << audio.outDeviceNames();
outDevCombobox->blockSignals(true);
outDevCombobox->clear();
@ -541,8 +540,8 @@ void AVForm::on_inDevCombobox_currentIndexChanged(int deviceIndex)
const QString oldName = audioSettings->getInDev();
if (oldName != deviceName) {
audioSettings->setInDev(deviceName);
audio->reinitInput(deviceName);
audioSrc = audio->makeSource();
audio.reinitInput(deviceName);
audioSrc = audio.makeSource();
connect(audioSrc.get(), &IAudioSource::volumeAvailable, this, &AVForm::setVolume);
}
@ -566,8 +565,8 @@ void AVForm::on_outDevCombobox_currentIndexChanged(int deviceIndex)
if (oldName != deviceName) {
audioSettings->setOutDev(deviceName);
audio->reinitOutput(deviceName);
audioSink = Audio::getInstance().makeSink();
audio.reinitOutput(deviceName);
audioSink = audio.makeSink();
}
playbackSlider->setEnabled(outputEnabled);
@ -579,10 +578,10 @@ void AVForm::on_playbackSlider_valueChanged(int sliderSteps)
audioSettings->getOutVolumeMax());
audioSettings->setOutVolume(settingsVolume);
if (audio->isOutputReady()) {
if (audio.isOutputReady()) {
const qreal volume =
getValueFromSteps(sliderSteps, audio->minOutputVolume(), audio->maxOutputVolume());
audio->setOutputVolume(volume);
getValueFromSteps(sliderSteps, audio.minOutputVolume(), audio.maxOutputVolume());
audio.setOutputVolume(volume);
if (cbEnableTestSound->isChecked() && audioSink) {
audioSink->playMono16Sound(IAudioSink::Sound::Test);
@ -594,24 +593,24 @@ void AVForm::on_cbEnableTestSound_stateChanged()
{
audioSettings->setEnableTestSound(cbEnableTestSound->isChecked());
if (cbEnableTestSound->isChecked() && audio->isOutputReady() && audioSink) {
if (cbEnableTestSound->isChecked() && audio.isOutputReady() && audioSink) {
audioSink->playMono16Sound(IAudioSink::Sound::Test);
}
}
void AVForm::on_microphoneSlider_valueChanged(int sliderSteps)
{
const qreal dB = getValueFromSteps(sliderSteps, audio->minInputGain(), audio->maxInputGain());
const qreal dB = getValueFromSteps(sliderSteps, audio.minInputGain(), audio.maxInputGain());
audioSettings->setAudioInGainDecibel(dB);
audio->setInputGain(dB);
audio.setInputGain(dB);
}
void AVForm::on_audioThresholdSlider_valueChanged(int sliderSteps)
{
const qreal normThreshold =
getValueFromSteps(sliderSteps, audio->minInputThreshold(), audio->maxInputThreshold());
getValueFromSteps(sliderSteps, audio.minInputThreshold(), audio.maxInputThreshold());
audioSettings->setAudioThreshold(normThreshold);
Audio::getInstance().setInputThreshold(normThreshold);
audio.setInputThreshold(normThreshold);
}
void AVForm::createVideoSurface()
{

View File

@ -30,7 +30,7 @@
#include <memory>
class Audio;
class IAudioControl;
class IAudioSettings;
class IAudioSink;
class IAudioSource;
@ -42,8 +42,8 @@ class AVForm : public GenericForm, private Ui::AVForm
{
Q_OBJECT
public:
AVForm(Audio* audio, CoreAV* coreAV, CameraSource& camera, IAudioSettings* audioSettings,
IVideoSettings* videoSettings);
AVForm(IAudioControl& audio, CoreAV* coreAV, CameraSource& camera,
IAudioSettings* audioSettings, IVideoSettings* videoSettings);
~AVForm() override;
QString getFormName() final override
{
@ -97,7 +97,7 @@ private:
qreal getValueFromSteps(int steps, qreal valMin, qreal valMax);
private:
Audio* audio;
IAudioControl& audio;
CoreAV* coreAV;
IAudioSettings* audioSettings;
IVideoSettings* videoSettings;

View File

@ -20,8 +20,8 @@
#include "settingswidget.h"
#include "src/audio/audio.h"
#include "src/core/coreav.h"
#include "src/core/core.h"
#include "src/core/coreav.h"
#include "src/net/updatecheck.h"
#include "src/persistence/settings.h"
#include "src/video/camerasource.h"
@ -41,10 +41,9 @@
#include <memory>
SettingsWidget::SettingsWidget(UpdateCheck* updateCheck, QWidget* parent)
SettingsWidget::SettingsWidget(UpdateCheck* updateCheck, IAudioControl& audio, QWidget* parent)
: QWidget(parent, Qt::Window)
{
Audio* audio = &Audio::getInstance();
CoreAV* coreAV = Core::getInstance()->getAv();
IAudioSettings* audioSettings = &Settings::getInstance();
IVideoSettings* videoSettings = &Settings::getInstance();
@ -74,7 +73,8 @@ SettingsWidget::SettingsWidget(UpdateCheck* updateCheck, QWidget* parent)
}
#endif
cfgForms = {{std::move(gfrm), std::move(uifrm), std::move(pfrm), std::move(avfrm), std::move(expfrm), std::move(abtfrm)}};
cfgForms = {{std::move(gfrm), std::move(uifrm), std::move(pfrm), std::move(avfrm),
std::move(expfrm), std::move(abtfrm)}};
for (auto& cfgForm : cfgForms)
settingsWidgets->addTab(cfgForm.get(), cfgForm->getFormIcon(), cfgForm->getFormName());

View File

@ -30,6 +30,7 @@
class Camera;
class GenericForm;
class GeneralForm;
class IAudioControl;
class PrivacyForm;
class AVForm;
class QLabel;
@ -41,7 +42,7 @@ class SettingsWidget : public QWidget
{
Q_OBJECT
public:
SettingsWidget(UpdateCheck* updateCheck, QWidget* parent = nullptr);
SettingsWidget(UpdateCheck* updateCheck, IAudioControl& audio, QWidget* parent = nullptr);
~SettingsWidget();
bool isShown() const;

View File

@ -52,16 +52,15 @@
#include "src/core/core.h"
#include "src/core/coreav.h"
#include "src/core/corefile.h"
#include "src/friendlist.h"
#include "src/grouplist.h"
#include "src/model/chatroom/friendchatroom.h"
#include "src/model/chatroom/groupchatroom.h"
#include "src/model/friend.h"
#include "src/friendlist.h"
#include "src/grouplist.h"
#include "src/model/friend.h"
#include "src/model/group.h"
#include "src/model/groupinvite.h"
#include "src/model/status.h"
#include "src/model/profile/profileinfo.h"
#include "src/model/status.h"
#include "src/net/updatecheck.h"
#include "src/nexus.h"
#include "src/persistence/offlinemsgengine.h"
@ -95,7 +94,7 @@ bool toxActivateEventHandler(const QByteArray&)
Widget* Widget::instance{nullptr};
Widget::Widget(QWidget* parent)
Widget::Widget(IAudioControl& audio, QWidget* parent)
: QMainWindow(parent)
, icon{nullptr}
, trayMenu{nullptr}
@ -103,6 +102,7 @@ Widget::Widget(QWidget* parent)
, activeChatroomWidget{nullptr}
, eventFlag(false)
, eventIcon(false)
, audio(audio)
, settings(Settings::getInstance())
{
installEventFilter(this);
@ -129,7 +129,8 @@ void Widget::init()
// Preparing icons and set their size
statusOnline = new QAction(this);
statusOnline->setIcon(prepareIcon(Status::getIconPath(Status::Status::Online), icon_size, icon_size));
statusOnline->setIcon(
prepareIcon(Status::getIconPath(Status::Status::Online), icon_size, icon_size));
connect(statusOnline, &QAction::triggered, this, &Widget::setStatusOnline);
statusAway = new QAction(this);
@ -148,7 +149,8 @@ void Widget::init()
actionQuit->setMenuRole(QAction::QuitRole);
#endif
actionQuit->setIcon(prepareIcon(Style::getImagePath("rejectCall/rejectCall.svg"), icon_size, icon_size));
actionQuit->setIcon(
prepareIcon(Style::getImagePath("rejectCall/rejectCall.svg"), icon_size, icon_size));
connect(actionQuit, &QAction::triggered, qApp, &QApplication::quit);
layout()->setContentsMargins(0, 0, 0, 0);
@ -233,7 +235,7 @@ void Widget::init()
updateCheck = std::unique_ptr<UpdateCheck>(new UpdateCheck(settings));
connect(updateCheck.get(), &UpdateCheck::updateAvailable, this, &Widget::onUpdateAvailable);
#endif
settingsWidget = new SettingsWidget(updateCheck.get(), this);
settingsWidget = new SettingsWidget(updateCheck.get(), audio, this);
#if UPDATE_CHECK_ENABLED
updateCheck->checkForUpdate();
#endif
@ -444,7 +446,6 @@ void Widget::updateIcons()
Status::getAssetSuffix(static_cast<Status::Status>(ui->statusButton->property("status").toInt()))
+ (eventIcon ? "_event" : "");
// Some builds of Qt appear to have a bug in icon loading:
// QIcon::hasThemeIcon is sometimes unaware that the icon returned
// from QIcon::fromTheme was a fallback icon, causing hasThemeIcon to
@ -538,12 +539,17 @@ Widget::~Widget()
}
/**
* @param audio Only used for initialization from Nexus, to pass IAudioControl
* @brief Returns the singleton instance.
*/
Widget* Widget::getInstance()
Widget* Widget::getInstance(IAudioControl* audio)
{
if (!instance) {
instance = new Widget();
// Passing audio via pointer here is a hack
// to allow for default paramters.
// once Widget::getInstance is removed it won't be neccessary
assert(audio != nullptr);
instance = new Widget(*audio);
}
return instance;
@ -587,8 +593,7 @@ void Widget::closeEvent(QCloseEvent* event)
void Widget::changeEvent(QEvent* event)
{
if (event->type() == QEvent::WindowStateChange) {
if (isMinimized() && settings.getShowSystemTray()
&& settings.getMinimizeToTray()) {
if (isMinimized() && settings.getShowSystemTray() && settings.getMinimizeToTray()) {
this->hide();
}
}
@ -916,8 +921,7 @@ void Widget::setStatusMessage(const QString& statusMessage)
ui->statusLabel->setText(statusMessage);
// escape HTML from tooltips and preserve newlines
// TODO: move newspace preservance to a generic function
ui->statusLabel->setToolTip("<p style='white-space:pre'>" + statusMessage.toHtmlEscaped()
+ "</p>");
ui->statusLabel->setToolTip("<p style='white-space:pre'>" + statusMessage.toHtmlEscaped() + "</p>");
}
void Widget::reloadHistory()
@ -932,19 +936,20 @@ void Widget::reloadHistory()
* @param sound Sound to play
* @param loop if true, loop the sound until onStopNotification() is called
*/
void Widget::playNotificationSound(IAudioSink::Sound sound, bool loop) {
if(audioNotification == nullptr) {
audioNotification = std::unique_ptr<IAudioSink>(Audio::getInstance().makeSink());
if(audioNotification == nullptr) {
void Widget::playNotificationSound(IAudioSink::Sound sound, bool loop)
{
if (audioNotification == nullptr) {
audioNotification = std::unique_ptr<IAudioSink>(audio.makeSink());
if (audioNotification == nullptr) {
qDebug() << "Failed to allocate AudioSink";
return;
}
}
connect(audioNotification.get(), &IAudioSink::finishedPlaying,
this, &Widget::cleanupNotificationSound);
connect(audioNotification.get(), &IAudioSink::finishedPlaying, this,
&Widget::cleanupNotificationSound);
if(loop) {
if (loop) {
audioNotification->startLoop();
}
@ -1011,7 +1016,8 @@ void Widget::addFriend(uint32_t friendId, const ToxPk& friendPk)
settings.setFriendActivity(friendPk, chatTime);
}
contactListWidget->addFriendWidget(widget, Status::Status::Offline, settings.getFriendCircleID(friendPk));
contactListWidget->addFriendWidget(widget, Status::Status::Offline,
settings.getFriendCircleID(friendPk));
connect(newfriend, &Friend::aliasChanged, this, &Widget::onFriendAliasChanged);
connect(newfriend, &Friend::displayedNameChanged, this, &Widget::onFriendDisplayedNameChanged);
@ -1249,7 +1255,8 @@ void Widget::addFriendDialog(const Friend* frnd, ContentDialog* dialog)
auto form = chatForms[friendPk];
auto chatroom = friendChatrooms[friendPk];
FriendWidget* friendWidget = ContentDialogManager::getInstance()->addFriendToDialog(dialog, chatroom, form);
FriendWidget* friendWidget =
ContentDialogManager::getInstance()->addFriendToDialog(dialog, chatroom, form);
friendWidget->setStatusMsg(widget->getStatusMsg());
@ -1305,7 +1312,8 @@ void Widget::addGroupDialog(Group* group, ContentDialog* dialog)
auto chatForm = groupChatForms[groupId].data();
auto chatroom = groupChatrooms[groupId];
auto groupWidget = ContentDialogManager::getInstance()->addGroupToDialog(dialog, chatroom, chatForm);
auto groupWidget =
ContentDialogManager::getInstance()->addGroupToDialog(dialog, chatroom, chatForm);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0))
auto removeGroup = QOverload<const GroupId&>::of(&Widget::removeGroup);
@ -1610,7 +1618,8 @@ ContentDialog* Widget::createContentDialog() const
connect(contentDialog, &ContentDialog::friendDialogShown, this, &Widget::onFriendDialogShown);
connect(contentDialog, &ContentDialog::groupDialogShown, this, &Widget::onGroupDialogShown);
connect(core, &Core::usernameSet, contentDialog, &ContentDialog::setUsername);
connect(&settings, &Settings::groupchatPositionChanged, contentDialog, &ContentDialog::reorderLayouts);
connect(&settings, &Settings::groupchatPositionChanged, contentDialog,
&ContentDialog::reorderLayouts);
#ifdef Q_OS_MAC
Nexus& n = Nexus::getInstance();
@ -1652,8 +1661,7 @@ ContentLayout* Widget::createContentDialog(DialogType type) const
void retranslateUi()
{
setWindowTitle(core->getUsername() + QStringLiteral(" - ")
+ Widget::fromDialogType(type));
setWindowTitle(core->getUsername() + QStringLiteral(" - ") + Widget::fromDialogType(type));
}
protected:
@ -1761,7 +1769,8 @@ void Widget::onGroupMessageReceived(int groupnumber, int peernumber, const QStri
return;
}
const auto mention = !core->getUsername().isEmpty() && (message.contains(nameMention) || message.contains(sanitizedNameMention));
const auto mention = !core->getUsername().isEmpty()
&& (message.contains(nameMention) || message.contains(sanitizedNameMention));
const auto targeted = !isSelf && mention;
const auto date = QDateTime::currentDateTime();
auto form = groupChatForms[groupId].data();
@ -1883,7 +1892,8 @@ Group* Widget::createGroup(uint32_t groupnumber, const GroupId& groupId)
const auto groupName = tr("Groupchat #%1").arg(groupnumber);
bool enabled = core->getGroupAvEnabled(groupnumber);
Group* newgroup = GroupList::addGroup(groupnumber, groupId, groupName, enabled, core->getUsername());
Group* newgroup =
GroupList::addGroup(groupnumber, groupId, groupName, enabled, core->getUsername());
std::shared_ptr<GroupChatroom> chatroom(new GroupChatroom(newgroup));
const auto compact = settings.getCompactLayout();
auto widget = new GroupWidget(chatroom, compact);
@ -1990,7 +2000,8 @@ void Widget::onUserAwayCheck()
{
#ifdef QTOX_PLATFORM_EXT
uint32_t autoAwayTime = settings.getAutoAwayTime() * 60 * 1000;
bool online = static_cast<Status::Status>(ui->statusButton->property("status").toInt()) == Status::Status::Online;
bool online = static_cast<Status::Status>(ui->statusButton->property("status").toInt())
== Status::Status::Online;
bool away = autoAwayTime && Platform::getIdleTime() >= autoAwayTime;
if (online && away) {
@ -2453,7 +2464,7 @@ void Widget::focusChatInput()
}
}
void Widget::refreshPeerListsLocal(const QString &username)
void Widget::refreshPeerListsLocal(const QString& username)
{
for (Group* g : GroupList::getAllGroups()) {
g->updateUsername(core->getSelfPublicKey(), username);

View File

@ -29,12 +29,13 @@
#include "genericchatitemwidget.h"
#include "src/audio/iaudiocontrol.h"
#include "src/audio/iaudiosink.h"
#include "src/core/core.h"
#include "src/core/toxfile.h"
#include "src/core/groupid.h"
#include "src/core/toxpk.h"
#include "src/core/toxfile.h"
#include "src/core/toxid.h"
#include "src/core/toxpk.h"
#if DESKTOP_NOTIFICATIONS
#include "src/platform/desktop_notifications/desktopnotify.h"
#endif
@ -112,13 +113,13 @@ private:
};
public:
explicit Widget(QWidget* parent = nullptr);
explicit Widget(IAudioControl& audio, QWidget* parent = nullptr);
~Widget() override;
void init();
void setCentralWidget(QWidget* widget, const QString& widgetName);
QString getUsername();
Camera* getCamera();
static Widget* getInstance();
static Widget* getInstance(IAudioControl* audio = nullptr);
void showUpdateDownloadProgress();
void addFriendDialog(const Friend* frnd, ContentDialog* dialog);
void addGroupDialog(Group* group, ContentDialog* dialog);
@ -185,7 +186,7 @@ public slots:
void onFriendDialogShown(const Friend* f);
void onGroupDialogShown(Group* g);
void toggleFullscreen();
void refreshPeerListsLocal(const QString &username);
void refreshPeerListsLocal(const QString& username);
void onUpdateAvailable(QString latestVersion, QUrl link);
signals:
@ -312,6 +313,8 @@ private:
QPushButton* groupInvitesButton;
unsigned int unreadGroupInvites;
int icon_size;
IAudioControl& audio;
std::unique_ptr<IAudioSink> audioNotification = nullptr;
Settings& settings;