output/pulse: implement Interrupt()
This commit is contained in:
parent
4ad525d939
commit
b80a135cf3
1
NEWS
1
NEWS
@ -1,6 +1,7 @@
|
||||
ver 0.22.1 (not yet released)
|
||||
* output
|
||||
- alsa: don't deadlock when the ALSA driver is buggy
|
||||
- pulse: reduce the delay when stopping or pausing playback
|
||||
|
||||
ver 0.22 (2020/09/23)
|
||||
* protocol
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "lib/pulse/LogError.hxx"
|
||||
#include "lib/pulse/LockGuard.hxx"
|
||||
#include "../OutputAPI.hxx"
|
||||
#include "../Error.hxx"
|
||||
#include "mixer/MixerList.hxx"
|
||||
#include "mixer/plugins/PulseMixerPlugin.hxx"
|
||||
#include "util/ScopeExit.hxx"
|
||||
@ -57,6 +58,15 @@ class PulseOutput final : AudioOutput {
|
||||
|
||||
bool pause;
|
||||
|
||||
/**
|
||||
* Was Interrupt() called? This will unblock Play(). It will
|
||||
* be reset by Cancel() and Pause(), as documented by the
|
||||
* #AudioOutput interface.
|
||||
*
|
||||
* Only initialized while the output is open.
|
||||
*/
|
||||
bool interrupted;
|
||||
|
||||
explicit PulseOutput(const ConfigBlock &block);
|
||||
|
||||
public:
|
||||
@ -99,6 +109,8 @@ public:
|
||||
void Open(AudioFormat &audio_format) override;
|
||||
void Close() noexcept override;
|
||||
|
||||
void Interrupt() noexcept override;
|
||||
|
||||
[[nodiscard]] std::chrono::steady_clock::duration Delay() const noexcept override;
|
||||
size_t Play(const void *chunk, size_t size) override;
|
||||
void Cancel() noexcept override;
|
||||
@ -677,6 +689,7 @@ PulseOutput::Open(AudioFormat &audio_format)
|
||||
}
|
||||
|
||||
pause = false;
|
||||
interrupted = false;
|
||||
}
|
||||
|
||||
void
|
||||
@ -704,6 +717,21 @@ PulseOutput::Close() noexcept
|
||||
DeleteContext();
|
||||
}
|
||||
|
||||
void
|
||||
PulseOutput::Interrupt() noexcept
|
||||
{
|
||||
if (mainloop == nullptr)
|
||||
return;
|
||||
|
||||
const Pulse::LockGuard lock(mainloop);
|
||||
|
||||
/* the "interrupted" flag will prevent Play() from blocking,
|
||||
and will instead throw AudioOutputInterrupted */
|
||||
interrupted = true;
|
||||
|
||||
Signal();
|
||||
}
|
||||
|
||||
void
|
||||
PulseOutput::WaitStream()
|
||||
{
|
||||
@ -719,6 +747,9 @@ PulseOutput::WaitStream()
|
||||
"failed to connect the stream");
|
||||
|
||||
case PA_STREAM_CREATING:
|
||||
if (interrupted)
|
||||
throw AudioOutputInterrupted{};
|
||||
|
||||
pa_threaded_mainloop_wait(mainloop);
|
||||
break;
|
||||
}
|
||||
@ -784,6 +815,9 @@ PulseOutput::Play(const void *chunk, size_t size)
|
||||
if (pa_stream_is_suspended(stream))
|
||||
throw std::runtime_error("suspended");
|
||||
|
||||
if (interrupted)
|
||||
throw AudioOutputInterrupted{};
|
||||
|
||||
pa_threaded_mainloop_wait(mainloop);
|
||||
|
||||
if (pa_stream_get_state(stream) != PA_STREAM_READY)
|
||||
@ -813,6 +847,7 @@ PulseOutput::Cancel() noexcept
|
||||
assert(stream != nullptr);
|
||||
|
||||
Pulse::LockGuard lock(mainloop);
|
||||
interrupted = false;
|
||||
|
||||
if (pa_stream_get_state(stream) != PA_STREAM_READY) {
|
||||
/* no need to flush when the stream isn't connected
|
||||
@ -842,6 +877,7 @@ PulseOutput::Pause()
|
||||
Pulse::LockGuard lock(mainloop);
|
||||
|
||||
pause = true;
|
||||
interrupted = false;
|
||||
|
||||
/* check if the stream is (already/still) connected */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user