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)
|
ver 0.22.1 (not yet released)
|
||||||
* output
|
* output
|
||||||
- alsa: don't deadlock when the ALSA driver is buggy
|
- 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)
|
ver 0.22 (2020/09/23)
|
||||||
* protocol
|
* protocol
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "lib/pulse/LogError.hxx"
|
#include "lib/pulse/LogError.hxx"
|
||||||
#include "lib/pulse/LockGuard.hxx"
|
#include "lib/pulse/LockGuard.hxx"
|
||||||
#include "../OutputAPI.hxx"
|
#include "../OutputAPI.hxx"
|
||||||
|
#include "../Error.hxx"
|
||||||
#include "mixer/MixerList.hxx"
|
#include "mixer/MixerList.hxx"
|
||||||
#include "mixer/plugins/PulseMixerPlugin.hxx"
|
#include "mixer/plugins/PulseMixerPlugin.hxx"
|
||||||
#include "util/ScopeExit.hxx"
|
#include "util/ScopeExit.hxx"
|
||||||
@ -57,6 +58,15 @@ class PulseOutput final : AudioOutput {
|
|||||||
|
|
||||||
bool pause;
|
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);
|
explicit PulseOutput(const ConfigBlock &block);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -99,6 +109,8 @@ public:
|
|||||||
void Open(AudioFormat &audio_format) override;
|
void Open(AudioFormat &audio_format) override;
|
||||||
void Close() noexcept override;
|
void Close() noexcept override;
|
||||||
|
|
||||||
|
void Interrupt() noexcept override;
|
||||||
|
|
||||||
[[nodiscard]] std::chrono::steady_clock::duration Delay() const noexcept override;
|
[[nodiscard]] std::chrono::steady_clock::duration Delay() const noexcept override;
|
||||||
size_t Play(const void *chunk, size_t size) override;
|
size_t Play(const void *chunk, size_t size) override;
|
||||||
void Cancel() noexcept override;
|
void Cancel() noexcept override;
|
||||||
@ -677,6 +689,7 @@ PulseOutput::Open(AudioFormat &audio_format)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pause = false;
|
pause = false;
|
||||||
|
interrupted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -704,6 +717,21 @@ PulseOutput::Close() noexcept
|
|||||||
DeleteContext();
|
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
|
void
|
||||||
PulseOutput::WaitStream()
|
PulseOutput::WaitStream()
|
||||||
{
|
{
|
||||||
@ -719,6 +747,9 @@ PulseOutput::WaitStream()
|
|||||||
"failed to connect the stream");
|
"failed to connect the stream");
|
||||||
|
|
||||||
case PA_STREAM_CREATING:
|
case PA_STREAM_CREATING:
|
||||||
|
if (interrupted)
|
||||||
|
throw AudioOutputInterrupted{};
|
||||||
|
|
||||||
pa_threaded_mainloop_wait(mainloop);
|
pa_threaded_mainloop_wait(mainloop);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -784,6 +815,9 @@ PulseOutput::Play(const void *chunk, size_t size)
|
|||||||
if (pa_stream_is_suspended(stream))
|
if (pa_stream_is_suspended(stream))
|
||||||
throw std::runtime_error("suspended");
|
throw std::runtime_error("suspended");
|
||||||
|
|
||||||
|
if (interrupted)
|
||||||
|
throw AudioOutputInterrupted{};
|
||||||
|
|
||||||
pa_threaded_mainloop_wait(mainloop);
|
pa_threaded_mainloop_wait(mainloop);
|
||||||
|
|
||||||
if (pa_stream_get_state(stream) != PA_STREAM_READY)
|
if (pa_stream_get_state(stream) != PA_STREAM_READY)
|
||||||
@ -813,6 +847,7 @@ PulseOutput::Cancel() noexcept
|
|||||||
assert(stream != nullptr);
|
assert(stream != nullptr);
|
||||||
|
|
||||||
Pulse::LockGuard lock(mainloop);
|
Pulse::LockGuard lock(mainloop);
|
||||||
|
interrupted = false;
|
||||||
|
|
||||||
if (pa_stream_get_state(stream) != PA_STREAM_READY) {
|
if (pa_stream_get_state(stream) != PA_STREAM_READY) {
|
||||||
/* no need to flush when the stream isn't connected
|
/* no need to flush when the stream isn't connected
|
||||||
@ -842,6 +877,7 @@ PulseOutput::Pause()
|
|||||||
Pulse::LockGuard lock(mainloop);
|
Pulse::LockGuard lock(mainloop);
|
||||||
|
|
||||||
pause = true;
|
pause = true;
|
||||||
|
interrupted = false;
|
||||||
|
|
||||||
/* check if the stream is (already/still) connected */
|
/* check if the stream is (already/still) connected */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user