output/alsa: add option "close_on_pause"
This allows keeping the ALSA PCM open even if playback is paused. As a side effect, this allows using the "always_on" option with ALSA outputs, because "always_on" pauses the output. Closes https://github.com/MusicPlayerDaemon/MPD/issues/1623
This commit is contained in:
parent
7ab789fbaf
commit
0a035f3ce0
1
NEWS
1
NEWS
|
@ -32,6 +32,7 @@ ver 0.24 (not yet released)
|
|||
- alsa: limit ALSA buffer time to 2 seconds
|
||||
- alsa: set up a channel map
|
||||
- alsa: support the alsa-lib 1.2.11 API
|
||||
- alsa: add option "close_on_pause"
|
||||
- curl: add "connect_timeout" configuration
|
||||
* decoder
|
||||
- ffmpeg: require FFmpeg 4.0 or later
|
||||
|
|
|
@ -896,6 +896,11 @@ The `Advanced Linux Sound Architecture (ALSA) <http://www.alsa-project.org/>`_ p
|
|||
|
||||
Example: "96000:16:* 192000:24:* dsd64:*=dop *:dsd:*".
|
||||
|
||||
* - **close_on_pause yes|no**
|
||||
- Close the ALSA device while playback is paused? This defaults
|
||||
to *yes* because this allows other applications to use the
|
||||
device while MPD is paused.
|
||||
|
||||
The according hardware mixer plugin understands the following settings:
|
||||
|
||||
.. list-table::
|
||||
|
|
|
@ -532,7 +532,8 @@ The following table lists the audio_output options valid for all plugins:
|
|||
- If set to yes, then :program:`MPD` attempts to keep this audio
|
||||
output always open. Instead of closing at the end
|
||||
of playback, it puts the device in "pause" mode. This works
|
||||
only with output plugins that suport "pause" mode.
|
||||
only with output plugins that suport "pause" mode (see
|
||||
:ref:`ALSA option "close_on_pause" <alsa_plugin>`).
|
||||
This may be useful for streaming servers, when you don't want
|
||||
to disconnect all listeners even when playback is accidentally
|
||||
stopped.
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <forward_list>
|
||||
|
||||
|
@ -222,6 +223,15 @@ class AlsaOutput final
|
|||
*/
|
||||
bool interrupted;
|
||||
|
||||
/**
|
||||
* Close the ALSA PCM while playback is paused? This defaults
|
||||
* to true because this allows other applications to use the
|
||||
* PCM while MPD is paused.
|
||||
*/
|
||||
const bool close_on_pause;
|
||||
|
||||
std::atomic_bool paused;
|
||||
|
||||
public:
|
||||
AlsaOutput(EventLoop &loop, const ConfigBlock &block);
|
||||
|
||||
|
@ -261,6 +271,7 @@ private:
|
|||
void Close() noexcept override;
|
||||
|
||||
void Interrupt() noexcept override;
|
||||
std::chrono::steady_clock::duration Delay() const noexcept override;
|
||||
|
||||
std::size_t Play(std::span<const std::byte> src) override;
|
||||
void Drain() override;
|
||||
|
@ -414,7 +425,7 @@ GetAlsaOpenMode(const ConfigBlock &block)
|
|||
}
|
||||
|
||||
AlsaOutput::AlsaOutput(EventLoop &_loop, const ConfigBlock &block)
|
||||
:AudioOutput(FLAG_ENABLE_DISABLE),
|
||||
:AudioOutput(FLAG_ENABLE_DISABLE|FLAG_PAUSE),
|
||||
MultiSocketMonitor(_loop),
|
||||
defer_invalidate_sockets(_loop, BIND_THIS_METHOD(InvalidateSockets)),
|
||||
silence_timer(_loop, BIND_THIS_METHOD(OnSilenceTimer)),
|
||||
|
@ -422,16 +433,16 @@ AlsaOutput::AlsaOutput(EventLoop &_loop, const ConfigBlock &block)
|
|||
buffer_time(block.GetPositiveValue("buffer_time",
|
||||
MPD_ALSA_BUFFER_TIME_US)),
|
||||
period_time(block.GetPositiveValue("period_time", 0U)),
|
||||
mode(GetAlsaOpenMode(block))
|
||||
mode(GetAlsaOpenMode(block)),
|
||||
#ifdef ENABLE_DSD
|
||||
,
|
||||
dop_setting(block.GetBlockValue("dop", false) ||
|
||||
/* legacy name from MPD 0.18 and older: */
|
||||
block.GetBlockValue("dsd_usb", false)),
|
||||
stop_dsd_silence(block.GetBlockValue("stop_dsd_silence", false)),
|
||||
thesycon_dsd_workaround(block.GetBlockValue("thesycon_dsd_workaround",
|
||||
false))
|
||||
false)),
|
||||
#endif
|
||||
close_on_pause(block.GetBlockValue("close_on_pause", true))
|
||||
{
|
||||
const char *allowed_formats_string =
|
||||
block.GetBlockValue("allowed_formats", nullptr);
|
||||
|
@ -752,6 +763,8 @@ Play_44_1_Silence(snd_pcm_t *pcm)
|
|||
void
|
||||
AlsaOutput::Open(AudioFormat &audio_format)
|
||||
{
|
||||
paused = false;
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
bool dop;
|
||||
#endif
|
||||
|
@ -866,6 +879,15 @@ AlsaOutput::Interrupt() noexcept
|
|||
cond.notify_one();
|
||||
}
|
||||
|
||||
std::chrono::steady_clock::duration
|
||||
AlsaOutput::Delay() const noexcept
|
||||
{
|
||||
if (paused)
|
||||
return std::chrono::hours{1};
|
||||
|
||||
return AudioOutput::Delay();
|
||||
}
|
||||
|
||||
inline int
|
||||
AlsaOutput::Recover(int err) noexcept
|
||||
{
|
||||
|
@ -1119,9 +1141,13 @@ AlsaOutput::Pause() noexcept
|
|||
std::lock_guard lock{mutex};
|
||||
interrupted = false;
|
||||
|
||||
/* not implemented - this override exists only to reset the
|
||||
"interrupted" flag */
|
||||
if (close_on_pause)
|
||||
return false;
|
||||
|
||||
// TODO use snd_pcm_pause()?
|
||||
|
||||
paused = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1188,6 +1214,8 @@ AlsaOutput::Play(std::span<const std::byte> src)
|
|||
assert(!src.empty());
|
||||
assert(src.size() % in_frame_size == 0);
|
||||
|
||||
paused = false;
|
||||
|
||||
const size_t max_frames = LockWaitWriteAvailable();
|
||||
const size_t max_size = max_frames * in_frame_size;
|
||||
if (src.size() > max_size)
|
||||
|
|
Loading…
Reference in New Issue