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

fix crash enabling PFL after deleting EffectState while PFL is disabled #1468

Merged
merged 5 commits into from
Jan 7, 2018
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
7 changes: 6 additions & 1 deletion src/effects/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ enum class EffectChainInsertionType {
Num_Insertion_Types
};

const int kNumEffectsPerUnit = 4;
constexpr int kNumEffectsPerUnit = 4;

// NOTE: Setting this to true will enable string manipulation and calls to
// qDebug() in the audio engine thread. That may cause audio dropouts, so only
// enable this when debugging the effects system.
constexpr bool kEffectDebugOutput = false;

class EffectState;
// For sending EffectStates along the MessagePipe
Expand Down
16 changes: 12 additions & 4 deletions src/effects/effectsmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,16 +441,24 @@ void EffectsManager::processEffectsResponses() {

void EffectsManager::collectGarbage(const EffectsRequest* pRequest) {
if (pRequest->type == EffectsRequest::REMOVE_EFFECT_FROM_CHAIN) {
//qDebug() << debugString() << "delete" << pRequest->RemoveEffectFromChain.pEffect;
if (kEffectDebugOutput) {
qDebug() << debugString() << "delete" << pRequest->RemoveEffectFromChain.pEffect;
}
delete pRequest->RemoveEffectFromChain.pEffect;
} else if (pRequest->type == EffectsRequest::REMOVE_CHAIN_FROM_RACK) {
//qDebug() << debugString() << "delete" << request->RemoveEffectFromChain.pEffect;
if (kEffectDebugOutput) {
qDebug() << debugString() << "delete" << pRequest->RemoveEffectFromChain.pEffect;
}
delete pRequest->RemoveChainFromRack.pChain;
} else if (pRequest->type == EffectsRequest::REMOVE_EFFECT_RACK) {
//qDebug() << debugString() << "delete" << pRequest->RemoveEffectRack.pRack;
if (kEffectDebugOutput) {
qDebug() << debugString() << "delete" << pRequest->RemoveEffectRack.pRack;
}
delete pRequest->RemoveEffectRack.pRack;
} else if (pRequest->type == EffectsRequest::DISABLE_EFFECT_CHAIN_FOR_INPUT_CHANNEL) {
//qDebug() << debugString() << "deleting states for input channel" << pRequest->channel << "for EngineEffectChain" << pRequest->pTargetChain;
if (kEffectDebugOutput) {
qDebug() << debugString() << "deleting states for input channel" << pRequest->DisableInputChannelForChain.pChannelHandle << "for EngineEffectChain" << pRequest->pTargetChain;
}
pRequest->pTargetChain->deleteStatesForInputChannel(
pRequest->DisableInputChannelForChain.pChannelHandle);
}
Expand Down
17 changes: 17 additions & 0 deletions src/engine/effects/engineeffectchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,23 @@ bool EngineEffectChain::disableForInputChannel(const ChannelHandle* inputHandle)

// Called from the main thread for garbage collection after an input channel is disabled
void EngineEffectChain::deleteStatesForInputChannel(const ChannelHandle* inputChannel) {
// If an output channel is not presently being processed, for example when
// PFL is not active, then process() cannot be relied upon to set this
// chain's EffectEnableState from Disabling to Disabled. This must be done
// before the next time process() is called for that output channel,
// otherwise, if any EngineEffects are Enabled,
// EffectProcessorImpl::processChannel will try to run
// with an EffectState that has already been deleted and cause a crash.
// Refer to https://bugs.launchpad.net/mixxx/+bug/1741213
// NOTE: ChannelHandleMap is like a map in that it associates an object with
// a ChannelHandle key, but it actually backed by a QVarLengthArray, not a
// QMap. So it is okay that m_chainStatusForChannelMatrix may be
// accessed concurrently in the audio engine thread in process(),
// enableForInputChannel(), or disableForInputChannel().
auto& outputMap = m_chainStatusForChannelMatrix[*inputChannel];
for (auto&& outputChannelStatus : outputMap) {
outputChannelStatus.enable_state = EffectEnableState::Disabled;
}
for (EngineEffect* pEffect : m_effects) {
if (pEffect != nullptr) {
pEffect->deleteStatesForInputChannel(inputChannel);
Expand Down
5 changes: 0 additions & 5 deletions src/engine/effects/message.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@
#include "effects/defs.h"
#include "engine/channelhandle.h"

// NOTE: Setting this to true will enable string manipulation and calls to
// qDebug() in the audio engine thread. That may cause audio dropouts, so only
// enable this when debugging the effects system.
const bool kEffectDebugOutput = false;

class EngineEffectRack;
class EngineEffectChain;
class EngineEffect;
Expand Down