fix: Fix a crash that would occur on exit if a ping sound played recently (#6332)
This commit is contained in:
@@ -40,6 +40,7 @@
|
|||||||
- Bugfix: Fixed a crash that could occur when eventsub was enabled and Chatterino was attached to a conhost on Windows that was later gone. (#6161)
|
- Bugfix: Fixed a crash that could occur when eventsub was enabled and Chatterino was attached to a conhost on Windows that was later gone. (#6161)
|
||||||
- Bugfix: Fixed a crash that could occur an eventsub connection's keepalive timer would run after the connection was dead, causing the keepalive timer to use-itself-after-free. (#6204)
|
- Bugfix: Fixed a crash that could occur an eventsub connection's keepalive timer would run after the connection was dead, causing the keepalive timer to use-itself-after-free. (#6204)
|
||||||
- Bugfix: Fixed a crash that could occur when an image started loading mid app shutdown. (#6213)
|
- Bugfix: Fixed a crash that could occur when an image started loading mid app shutdown. (#6213)
|
||||||
|
- Bugfix: Fixed a crash that could occur on exit if a ping played less than 30 seconds prior. (#6332)
|
||||||
- Bugfix: Fixed notebook buttons (settings, account switcher, streamer mode) not performing a relayout when their visibility changed, causing a gap until resize. Linux / macOS only. (#6328)
|
- Bugfix: Fixed notebook buttons (settings, account switcher, streamer mode) not performing a relayout when their visibility changed, causing a gap until resize. Linux / macOS only. (#6328)
|
||||||
- Bugfix: Fixed some minor typos. (#6196)
|
- Bugfix: Fixed some minor typos. (#6196)
|
||||||
- Bugfix: Fixed inconsistent spaces in messages when using fractional scaling. (#6231, #6254)
|
- Bugfix: Fixed inconsistent spaces in messages when using fractional scaling. (#6231, #6254)
|
||||||
|
|||||||
@@ -1,22 +1,17 @@
|
|||||||
#include "controllers/sound/MiniaudioBackend.hpp"
|
#include "controllers/sound/MiniaudioBackend.hpp"
|
||||||
|
|
||||||
#include "Application.hpp"
|
|
||||||
#include "common/QLogging.hpp"
|
#include "common/QLogging.hpp"
|
||||||
#include "debug/Benchmark.hpp"
|
#include "debug/Benchmark.hpp"
|
||||||
#include "singletons/Paths.hpp"
|
#include "util/QMagicEnum.hpp"
|
||||||
#include "singletons/Settings.hpp"
|
|
||||||
#include "singletons/WindowManager.hpp"
|
|
||||||
#include "util/RenameThread.hpp"
|
#include "util/RenameThread.hpp"
|
||||||
#include "widgets/Window.hpp"
|
|
||||||
|
|
||||||
#include <boost/asio/executor_work_guard.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
|
||||||
#define MINIAUDIO_IMPLEMENTATION
|
#define MINIAUDIO_IMPLEMENTATION
|
||||||
#include <miniaudio.h>
|
#include <miniaudio.h>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QScopeGuard>
|
#include <QScopeGuard>
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -89,6 +84,7 @@ MiniaudioBackend::MiniaudioBackend()
|
|||||||
{
|
{
|
||||||
qCWarning(chatterinoSound)
|
qCWarning(chatterinoSound)
|
||||||
<< "Error initializing logger:" << result;
|
<< "Error initializing logger:" << result;
|
||||||
|
this->state = State::Failed;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +94,7 @@ MiniaudioBackend::MiniaudioBackend()
|
|||||||
{
|
{
|
||||||
qCWarning(chatterinoSound)
|
qCWarning(chatterinoSound)
|
||||||
<< "Error registering logger callback:" << result;
|
<< "Error registering logger callback:" << result;
|
||||||
|
this->state = State::Failed;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +108,7 @@ MiniaudioBackend::MiniaudioBackend()
|
|||||||
{
|
{
|
||||||
qCWarning(chatterinoSound)
|
qCWarning(chatterinoSound)
|
||||||
<< "Error initializing context:" << result;
|
<< "Error initializing context:" << result;
|
||||||
|
this->state = State::Failed;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +117,7 @@ MiniaudioBackend::MiniaudioBackend()
|
|||||||
if (!defaultPingFile.open(QIODevice::ReadOnly))
|
if (!defaultPingFile.open(QIODevice::ReadOnly))
|
||||||
{
|
{
|
||||||
qCWarning(chatterinoSound) << "Error loading default ping sound";
|
qCWarning(chatterinoSound) << "Error loading default ping sound";
|
||||||
|
this->state = State::Failed;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->defaultPingData = defaultPingFile.readAll();
|
this->defaultPingData = defaultPingFile.readAll();
|
||||||
@@ -133,6 +132,7 @@ MiniaudioBackend::MiniaudioBackend()
|
|||||||
{
|
{
|
||||||
qCWarning(chatterinoSound)
|
qCWarning(chatterinoSound)
|
||||||
<< "Error initializing engine:" << result;
|
<< "Error initializing engine:" << result;
|
||||||
|
this->state = State::Failed;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,6 +168,7 @@ MiniaudioBackend::MiniaudioBackend()
|
|||||||
qCWarning(chatterinoSound) << "Error initializing default "
|
qCWarning(chatterinoSound) << "Error initializing default "
|
||||||
"ping decoder from memory:"
|
"ping decoder from memory:"
|
||||||
<< result;
|
<< result;
|
||||||
|
this->state = State::Failed;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,6 +180,7 @@ MiniaudioBackend::MiniaudioBackend()
|
|||||||
qCWarning(chatterinoSound)
|
qCWarning(chatterinoSound)
|
||||||
<< "Error initializing default sound from data source:"
|
<< "Error initializing default sound from data source:"
|
||||||
<< result;
|
<< result;
|
||||||
|
this->state = State::Failed;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +191,7 @@ MiniaudioBackend::MiniaudioBackend()
|
|||||||
|
|
||||||
qCInfo(chatterinoSound) << "miniaudio sound system initialized";
|
qCInfo(chatterinoSound) << "miniaudio sound system initialized";
|
||||||
|
|
||||||
this->initialized = true;
|
this->state = State::Initialized;
|
||||||
});
|
});
|
||||||
|
|
||||||
this->audioThread = std::make_unique<std::thread>([this] {
|
this->audioThread = std::make_unique<std::thread>([this] {
|
||||||
@@ -204,8 +206,7 @@ MiniaudioBackend::MiniaudioBackend()
|
|||||||
|
|
||||||
MiniaudioBackend::~MiniaudioBackend()
|
MiniaudioBackend::~MiniaudioBackend()
|
||||||
{
|
{
|
||||||
// NOTE: This destructor is never called because the `runGui` function calls _exit before that happens
|
this->state = State::Stopping;
|
||||||
// I have manually called the destructor prior to _exit being called to ensure this logic is sound
|
|
||||||
|
|
||||||
boost::asio::post(this->ioContext, [this] {
|
boost::asio::post(this->ioContext, [this] {
|
||||||
for (const auto &snd : this->defaultPingSounds)
|
for (const auto &snd : this->defaultPingSounds)
|
||||||
@@ -219,37 +220,43 @@ MiniaudioBackend::~MiniaudioBackend()
|
|||||||
|
|
||||||
ma_engine_uninit(this->engine.get());
|
ma_engine_uninit(this->engine.get());
|
||||||
ma_context_uninit(this->context.get());
|
ma_context_uninit(this->context.get());
|
||||||
|
|
||||||
this->workGuard.reset();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!this->audioThread->joinable())
|
this->workGuard.reset();
|
||||||
{
|
this->sleepTimer.cancel();
|
||||||
qCWarning(chatterinoSound) << "Audio thread not joinable";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->stoppedFlag.waitFor(std::chrono::seconds{1}))
|
if (this->audioThread->joinable())
|
||||||
{
|
{
|
||||||
this->audioThread->join();
|
if (this->stoppedFlag.waitFor(std::chrono::seconds{1}))
|
||||||
return;
|
{
|
||||||
}
|
this->audioThread->join();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
qCWarning(chatterinoSound) << "Audio thread did not stop within 1 second";
|
qCWarning(chatterinoSound)
|
||||||
this->audioThread->detach();
|
<< "Audio thread did not stop within 1 second";
|
||||||
|
this->audioThread->detach();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MiniaudioBackend::play(const QUrl &sound)
|
void MiniaudioBackend::play(const QUrl &sound)
|
||||||
{
|
{
|
||||||
|
if (this->state != State::Initialized)
|
||||||
|
{
|
||||||
|
qCWarning(chatterinoSound) << "Can't play sound, sound controller "
|
||||||
|
"is not initialized";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
boost::asio::post(this->ioContext, [this, sound] {
|
boost::asio::post(this->ioContext, [this, sound] {
|
||||||
static size_t i = 0;
|
static size_t i = 0;
|
||||||
|
|
||||||
this->tgPlay.guard();
|
this->tgPlay.guard();
|
||||||
|
|
||||||
if (!this->initialized)
|
if (this->state != State::Initialized)
|
||||||
{
|
{
|
||||||
qCWarning(chatterinoSound) << "Can't play sound, sound controller "
|
qCWarning(chatterinoSound) << "Can't play sound, sound controller "
|
||||||
"didn't initialize correctly";
|
"is not initialized";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,18 @@
|
|||||||
#include "util/OnceFlag.hpp"
|
#include "util/OnceFlag.hpp"
|
||||||
#include "util/ThreadGuard.hpp"
|
#include "util/ThreadGuard.hpp"
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio/executor_work_guard.hpp>
|
||||||
|
#include <boost/asio/io_context.hpp>
|
||||||
|
#include <boost/asio/steady_timer.hpp>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct ma_engine;
|
struct ma_engine;
|
||||||
@@ -26,6 +32,15 @@ namespace chatterino {
|
|||||||
**/
|
**/
|
||||||
class MiniaudioBackend : public ISoundController
|
class MiniaudioBackend : public ISoundController
|
||||||
{
|
{
|
||||||
|
enum class State : std::uint8_t {
|
||||||
|
Uninitialized,
|
||||||
|
Initialized,
|
||||||
|
Failed,
|
||||||
|
Stopping,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::atomic<State> state{State::Uninitialized};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MiniaudioBackend();
|
MiniaudioBackend();
|
||||||
~MiniaudioBackend() override;
|
~MiniaudioBackend() override;
|
||||||
@@ -63,8 +78,6 @@ private:
|
|||||||
OnceFlag stoppedFlag;
|
OnceFlag stoppedFlag;
|
||||||
boost::asio::steady_timer sleepTimer;
|
boost::asio::steady_timer sleepTimer;
|
||||||
|
|
||||||
bool initialized{false};
|
|
||||||
|
|
||||||
friend class Application;
|
friend class Application;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user