11using Notifier = QAudioStateMachine::Notifier;
14QAudioStateMachine::QAudioStateMachine(QAudioStateChangeNotifier ¬ifier) : m_notifier(¬ifier)
18QAudioStateMachine::~QAudioStateMachine() =
default;
20QAudio::State QAudioStateMachine::state()
const
22 return toAudioState(m_state.load(std::memory_order_acquire));
25QAudio::Error QAudioStateMachine::error()
const
27 return toAudioError(m_state.load(std::memory_order_acquire));
30template <
typename StatesChecker,
typename NewState>
31Notifier QAudioStateMachine::changeState(
const StatesChecker &checker,
const NewState &newState)
33 if constexpr (std::is_same_v<RawState, NewState>)
34 return changeState(checker, [newState](RawState) {
return newState; });
36 RawState prevState = m_state.load(std::memory_order_relaxed);
37 const auto exchanged = multipleCompareExchange(m_state, prevState, checker, newState);
39 if (Q_LIKELY(exchanged))
40 return {
this, newState(prevState), prevState };
46Notifier QAudioStateMachine::stop(QAudio::Error error,
bool shouldDrain,
bool forceUpdateError)
49 makeStatesChecker(QAudio::ActiveState, QAudio::IdleState, QAudio::SuspendedState,
50 forceUpdateError ? QAudio::StoppedState : QAudio::ActiveState);
52 const auto state = toRawState(QAudio::StoppedState, error);
53 auto getNewState = [&](RawState prevState) {
54 const bool shouldAddFlag = shouldDrain && toAudioState(prevState) == QAudio::ActiveState;
55 return shouldAddFlag ? addDrainingFlag(state) : state;
58 return changeState(statesChecker, getNewState);
61Notifier QAudioStateMachine::start(RunningState activeOrIdle)
63 return changeState(makeStatesChecker(QAudio::StoppedState),
64 toRawState(
static_cast<QtAudio::State>(activeOrIdle)));
67bool QAudioStateMachine::isActiveOrIdle()
const
69 const auto state =
this->state();
70 return state == QAudio::ActiveState || state == QAudio::IdleState;
73bool QAudioStateMachine::onDrained()
75 return changeState(isDrainingState, removeDrainingFlag);
78bool QAudioStateMachine::isDraining()
const
80 return isDrainingState(m_state.load(std::memory_order_acquire));
83std::pair<
bool,
bool> QAudioStateMachine::getDrainedAndStopped()
const
85 const auto state = m_state.load(std::memory_order_acquire);
86 return { !isDrainingState(state), toAudioState(state) == QAudio::StoppedState };
89Notifier QAudioStateMachine::suspend()
93 const auto error = QAudio::NoError;
94 auto result = changeState(makeStatesChecker(QAudio::ActiveState, QAudio::IdleState),
95 toRawState(QAudio::SuspendedState, error));
98 m_suspendedInState = result.prevAudioState();
103Notifier QAudioStateMachine::resume()
107 const auto error = QAudio::NoError;
108 return changeState(makeStatesChecker(QAudio::SuspendedState),
109 toRawState(m_suspendedInState, error));
112Notifier QAudioStateMachine::activateFromIdle()
114 return changeState(makeStatesChecker(QAudio::IdleState), toRawState(QAudio::ActiveState));
117Notifier QAudioStateMachine::updateActiveOrIdle(RunningState activeOrIdle, QAudio::Error error)
119 return changeState(makeStatesChecker(QAudio::ActiveState, QAudio::IdleState),
120 toRawState(
static_cast<QtAudio::State>(activeOrIdle), error));
123Notifier QAudioStateMachine::setError(QAudio::Error error)
125 auto fixState = [error](RawState prevState) {
return setStateError(prevState, error); };
126 return changeState([](RawState) {
return true; }, fixState);
129Notifier QAudioStateMachine::forceSetState(QAudio::State state, QAudio::Error error)
131 return changeState([](RawState) {
return true; }, toRawState(state, error));
134void QAudioStateMachine::reset(RawState state, RawState prevState)
136 auto notifier = m_notifier;
138 const auto audioState = toAudioState(state);
139 const auto audioError = toAudioError(state);
141 if (toAudioState(prevState) != audioState && notifier)
142 emit notifier->stateChanged(audioState);
145 if (toAudioError(prevState) != audioError && notifier)
146 emit notifier->errorChanged(audioError);
Combined button and popup list for selecting options.