Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recreate ma_device on failure #4729

Merged
merged 3 commits into from
Jul 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- Bugfix: Fixed partially broken filters on Qt 6 builds. (#4702)
- Bugfix: Fixed some network errors having `0` as their HTTP status. (#4704)
- Bugfix: Fixed crash that could occurr when closing the usercard too quickly after blocking or unblocking a user. (#4711)
- Bugfix: Fixed highlights sometimes not working after changing sound device, or switching users in your operating system. (#4729)
- Bugfix: Fixed key bindings not showing in context menus on Mac. (#4722)
- Dev: Added command to set Qt's logging filter/rules at runtime (`/c2-set-logging-rules`). (#4637)
- Dev: Added the ability to see & load custom themes from the Themes directory. No stable promises are made of this feature, changes might be made that breaks custom themes without notice. (#4570)
Expand Down
76 changes: 53 additions & 23 deletions src/controllers/sound/SoundController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ constexpr const auto NUM_SOUNDS = 4;
SoundController::SoundController()
: context(std::make_unique<ma_context>())
, resourceManager(std::make_unique<ma_resource_manager>())
, device(std::make_unique<ma_device>())
, engine(std::make_unique<ma_engine>())
{
}
Expand Down Expand Up @@ -66,27 +65,9 @@ void SoundController::initialize(Settings &settings, Paths &paths)
this->defaultPingData = defaultPingFile.readAll();

/// Initialize a sound device
auto deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.playback.pDeviceID = nullptr;
deviceConfig.playback.format = this->resourceManager->config.decodedFormat;
deviceConfig.playback.channels = 0;
deviceConfig.pulse.pStreamNamePlayback = "Chatterino MA";
deviceConfig.sampleRate = this->resourceManager->config.decodedSampleRate;
deviceConfig.dataCallback = ma_engine_data_callback_internal;
deviceConfig.pUserData = this->engine.get();

result =
ma_device_init(this->context.get(), &deviceConfig, this->device.get());
if (result != MA_SUCCESS)
if (!this->recreateDevice())
{
qCWarning(chatterinoSound) << "Error initializing device:" << result;
return;
}

result = ma_device_start(this->device.get());
if (result != MA_SUCCESS)
{
qCWarning(chatterinoSound) << "Error starting device:" << result;
qCWarning(chatterinoSound) << "Failed to create the initial device";
return;
}

Expand Down Expand Up @@ -172,7 +153,11 @@ SoundController::~SoundController()
}

ma_engine_uninit(this->engine.get());
ma_device_uninit(this->device.get());
if (this->device)
{
ma_device_uninit(this->device.get());
this->device.reset();
}
ma_resource_manager_uninit(this->resourceManager.get());
ma_context_uninit(this->context.get());
}
Expand Down Expand Up @@ -204,7 +189,12 @@ void SoundController::play(const QUrl &sound)
{
qCWarning(chatterinoSound)
<< "Failed to start the sound device" << result;
return;

if (!this->recreateDevice())
{
qCWarning(chatterinoSound) << "Failed to recreate device";
return;
}
}

qCInfo(chatterinoSound) << "Successfully restarted the sound device";
Expand Down Expand Up @@ -234,4 +224,44 @@ void SoundController::play(const QUrl &sound)
}
}

bool SoundController::recreateDevice()
{
ma_result result{};

if (this->device)
{
// Release the previous device first
qCDebug(chatterinoSound) << "Uniniting previously created device";
ma_device_uninit(this->device.get());
}

this->device = std::make_unique<ma_device>();

auto deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.playback.pDeviceID = nullptr;
deviceConfig.playback.format = this->resourceManager->config.decodedFormat;
deviceConfig.playback.channels = 0;
deviceConfig.pulse.pStreamNamePlayback = "Chatterino MA";
deviceConfig.sampleRate = this->resourceManager->config.decodedSampleRate;
deviceConfig.dataCallback = ma_engine_data_callback_internal;
deviceConfig.pUserData = this->engine.get();

result =
ma_device_init(this->context.get(), &deviceConfig, this->device.get());
if (result != MA_SUCCESS)
{
qCWarning(chatterinoSound) << "Error initializing device:" << result;
return false;
}

result = ma_device_start(this->device.get());
if (result != MA_SUCCESS)
{
qCWarning(chatterinoSound) << "Error starting device:" << result;
return false;
}

return true;
}

} // namespace chatterino
9 changes: 8 additions & 1 deletion src/controllers/sound/SoundController.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class SoundController : public Singleton
// Used for storing & reusing sounds to be played
std::unique_ptr<ma_resource_manager> resourceManager;
// The sound device we're playing sound into
std::unique_ptr<ma_device> device;
std::unique_ptr<ma_device> device{nullptr};
// The engine is a high-level API for playing sounds from paths in a simple & efficient-enough manner
std::unique_ptr<ma_engine> engine;

Expand All @@ -64,6 +64,13 @@ class SoundController : public Singleton

bool initialized{false};

// Recreates the sound device
// This is used during initialization, and can also be used if the device
// needs to be recreated during playback
//
// Returns false on failure
bool recreateDevice();

friend class Application;
};

Expand Down
Loading