AlsaOutputPlugin.cxx 27.1 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright 2003-2020 The Music Player Daemon Project
3
 * http://www.musicpd.org
4 5 6 7 8 9 10 11 12 13
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
14 15 16 17
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 19
 */

20
#include "config.h"
21
#include "AlsaOutputPlugin.hxx"
22
#include "lib/alsa/AllowedFormat.hxx"
23
#include "lib/alsa/HwSetup.hxx"
24
#include "lib/alsa/NonBlock.hxx"
25
#include "lib/alsa/PeriodBuffer.hxx"
26
#include "lib/alsa/Version.hxx"
27
#include "../OutputAPI.hxx"
Max Kellermann's avatar
Max Kellermann committed
28
#include "mixer/MixerList.hxx"
29
#include "pcm/Export.hxx"
30
#include "system/PeriodClock.hxx"
31
#include "thread/Mutex.hxx"
32
#include "thread/Cond.hxx"
33
#include "util/Manual.hxx"
34
#include "util/RuntimeError.hxx"
35
#include "util/Domain.hxx"
36
#include "util/ConstBuffer.hxx"
37
#include "util/StringView.hxx"
38
#include "event/MultiSocketMonitor.hxx"
39
#include "event/DeferEvent.hxx"
40
#include "event/Call.hxx"
41
#include "Log.hxx"
42

43
#include <alsa/asoundlib.h>
44

45 46
#include <boost/lockfree/spsc_queue.hpp>

47
#include <string>
48
#include <forward_list>
49

50 51
static const char default_device[] = "default";

52
static constexpr unsigned MPD_ALSA_BUFFER_TIME_US = 500000;
53

54
class AlsaOutput final
55 56 57
	: AudioOutput, MultiSocketMonitor {

	DeferEvent defer_invalidate_sockets;
58

59 60 61 62 63 64 65 66 67
	/**
	 * This timer is used to re-schedule the #MultiSocketMonitor
	 * after it had been disabled to wait for the next Play() call
	 * to deliver more data.  This timer is necessary to start
	 * generating silence if Play() doesn't get called soon enough
	 * to avoid the xrun.
	 */
	TimerEvent silence_timer;

68 69
	PeriodClock throttle_silence_log;

70
	Manual<PcmExport> pcm_export;
71

72 73 74 75
	/**
	 * The configured name of the ALSA device; empty for the
	 * default device
	 */
76
	const std::string device;
77

78
#ifdef ENABLE_DSD
79
	/**
Max Kellermann's avatar
Max Kellermann committed
80
	 * Enable DSD over PCM according to the DoP standard?
81
	 *
82
	 * @see http://dsd-guide.com/dop-open-standard
83
	 */
84
	bool dop_setting;
85
#endif
86

Max Kellermann's avatar
Max Kellermann committed
87
	/** libasound's buffer_time setting (in microseconds) */
88
	const unsigned buffer_time;
Max Kellermann's avatar
Max Kellermann committed
89 90

	/** libasound's period_time setting (in microseconds) */
91
	const unsigned period_time;
Max Kellermann's avatar
Max Kellermann committed
92

93
	/** the mode flags passed to snd_pcm_open */
94
	int mode = 0;
95

96 97
	std::forward_list<Alsa::AllowedFormat> allowed_formats;

98 99 100 101 102
	/**
	 * Protects #dop_setting and #allowed_formats.
	 */
	mutable Mutex attributes_mutex;

Max Kellermann's avatar
Max Kellermann committed
103
	/** the libasound PCM device handle */
Max Kellermann's avatar
Max Kellermann committed
104
	snd_pcm_t *pcm;
Max Kellermann's avatar
Max Kellermann committed
105

106 107 108 109 110 111 112 113 114
	/**
	 * The size of one audio frame passed to method play().
	 */
	size_t in_frame_size;

	/**
	 * The size of one audio frame passed to libasound.
	 */
	size_t out_frame_size;
115 116 117 118 119 120

	/**
	 * The size of one period, in number of frames.
	 */
	snd_pcm_uframes_t period_frames;

121 122
	std::chrono::steady_clock::duration effective_period_duration;

123 124 125 126 127 128 129
	/**
	 * If snd_pcm_avail() goes above this value and no more data
	 * is available in the #ring_buffer, we need to play some
	 * silence.
	 */
	snd_pcm_sframes_t max_avail_frames;

130 131 132 133 134 135 136 137 138 139 140
	/**
	 * Is this a buggy alsa-lib version, which needs a workaround
	 * for the snd_pcm_drain() bug always returning -EAGAIN?  See
	 * alsa-lib commits fdc898d41135 and e4377b16454f for details.
	 * This bug was fixed in alsa-lib version 1.1.4.
	 *
	 * The workaround is to re-enable blocking mode for the
	 * snd_pcm_drain() call.
	 */
	bool work_around_drain_bug;

141
	/**
142 143
	 * After Open() or Cancel(), has this output been activated by
	 * a Play() command?
144
	 *
145
	 * Protected by #mutex.
146
	 */
147
	bool active;
148

149 150 151 152 153 154 155
	/**
	 * Is this output waiting for more data?
	 *
	 * Protected by #mutex.
	 */
	bool waiting;

156
	/**
157 158 159 160 161 162 163 164
	 * Do we need to call snd_pcm_prepare() before the next write?
	 * It means that we put the device to SND_PCM_STATE_SETUP by
	 * calling snd_pcm_drop().
	 *
	 * Without this flag, we could easily recover after a failed
	 * optimistic write (returning -EBADFD), but the Raspberry Pi
	 * audio driver is infamous for generating ugly artefacts from
	 * this.
165
	 */
166
	bool must_prepare;
167

168 169 170 171 172 173 174 175 176 177
	/**
	 * Has snd_pcm_writei() been called successfully at least once
	 * since the PCM was prepared?
	 *
	 * This is necessary to work around a kernel bug which causes
	 * snd_pcm_drain() to return -EAGAIN forever in non-blocking
	 * mode if snd_pcm_writei() was never called.
	 */
	bool written;

178 179
	bool drain;

180 181 182 183 184
	/**
	 * This buffer gets allocated after opening the ALSA device.
	 * It contains silence samples, enough to fill one period (see
	 * #period_frames).
	 */
185
	uint8_t *silence;
186

187
	AlsaNonBlockPcm non_block;
188 189 190 191 192 193

	/**
	 * For copying data from OutputThread to IOThread.
	 */
	boost::lockfree::spsc_queue<uint8_t> *ring_buffer;

194
	Alsa::PeriodBuffer period_buffer;
195 196

	/**
197
	 * Protects #cond, #error, #active, #waiting, #drain.
198 199 200 201 202 203 204 205 206 207 208 209
	 */
	mutable Mutex mutex;

	/**
	 * Used to wait when #ring_buffer is full.  It will be
	 * signalled each time data is popped from the #ring_buffer,
	 * making space for more data.
	 */
	Cond cond;

	std::exception_ptr error;

210
public:
211
	AlsaOutput(EventLoop &loop, const ConfigBlock &block);
212

213
	~AlsaOutput() noexcept override {
214 215 216 217
		/* free libasound's config cache */
		snd_config_update_free_global();
	}

218 219
	using MultiSocketMonitor::GetEventLoop;

220
	gcc_pure
221
	const char *GetDevice() const noexcept {
222 223 224
		return device.empty() ? default_device : device.c_str();
	}

225 226 227 228
	static AudioOutput *Create(EventLoop &event_loop,
				   const ConfigBlock &block) {
		return new AlsaOutput(event_loop, block);
	}
229

230
private:
231
	std::map<std::string, std::string> GetAttributes() const noexcept override;
232 233
	void SetAttribute(std::string &&name, std::string &&value) override;

234 235
	void Enable() override;
	void Disable() noexcept override;
236

237 238
	void Open(AudioFormat &audio_format) override;
	void Close() noexcept override;
239

240 241 242
	size_t Play(const void *chunk, size_t size) override;
	void Drain() override;
	void Cancel() noexcept override;
243

244 245 246 247
	/**
	 * Set up the snd_pcm_t object which was opened by the caller.
	 * Set up the configured settings and the audio format.
	 *
248
	 * Throws on error.
249 250 251
	 */
	void Setup(AudioFormat &audio_format, PcmExport::Params &params);

252
#ifdef ENABLE_DSD
253 254
	void SetupDop(AudioFormat audio_format,
		      PcmExport::Params &params);
255 256
#endif

257 258 259 260 261
	void SetupOrDop(AudioFormat &audio_format, PcmExport::Params &params
#ifdef ENABLE_DSD
			, bool dop
#endif
			);
262

263 264 265 266 267 268
	gcc_pure
	bool LockIsActive() const noexcept {
		const std::lock_guard<Mutex> lock(mutex);
		return active;
	}

269 270 271 272 273 274
	gcc_pure
	bool LockIsActiveAndNotWaiting() const noexcept {
		const std::lock_guard<Mutex> lock(mutex);
		return active && !waiting;
	}

275 276 277 278 279
	/**
	 * Activate the output by registering the sockets in the
	 * #EventLoop.  Before calling this, filling the ring buffer
	 * has no effect; nothing will be played, and no code will be
	 * run on #EventLoop's thread.
280 281
	 *
	 * Caller must hold the mutex.
282 283 284
	 *
	 * @return true if Activate() was called, false if the mutex
	 * was never unlocked
285
	 */
286
	bool Activate() noexcept {
287
		if (active && !waiting)
288
			return false;
289

290
		active = true;
291
		waiting = false;
292

293
		const ScopeUnlock unlock(mutex);
294
		defer_invalidate_sockets.Schedule();
295
		return true;
296 297
	}

298 299 300 301 302 303 304 305 306 307 308
	/**
	 * Wait until there is some space available in the ring buffer.
	 *
	 * Caller must not lock the mutex.
	 *
	 * Throws on error.
	 *
	 * @return the number of frames available for writing
	 */
	size_t LockWaitWriteAvailable();

309
	int Recover(int err) noexcept;
310 311

	/**
312 313
	 * Drain all buffers.  To be run in #EventLoop's thread.
	 *
314 315
	 * Throws on error.
	 *
316 317
	 * @return true if draining is complete, false if this method
	 * needs to be called again later
318
	 */
319
	bool DrainInternal();
320 321 322 323 324

	/**
	 * Stop playback immediately, dropping all buffers.  To be run
	 * in #EventLoop's thread.
	 */
325
	void CancelInternal() noexcept;
326

327 328 329 330
	/**
	 * @return false if no data was moved
	 */
	bool CopyRingToPeriodBuffer() noexcept {
331
		if (period_buffer.IsFull())
332
			return false;
333 334 335 336

		size_t nbytes = ring_buffer->pop(period_buffer.GetTail(),
						 period_buffer.GetSpaceBytes());
		if (nbytes == 0)
337
			return false;
338 339 340 341 342 343

		period_buffer.AppendBytes(nbytes);

		const std::lock_guard<Mutex> lock(mutex);
		/* notify the OutputThread that there is now
		   room in ring_buffer */
344
		cond.notify_one();
345 346

		return true;
347 348
	}

349
	snd_pcm_sframes_t WriteFromPeriodBuffer() noexcept {
350
		assert(period_buffer.IsFull());
351
		assert(period_buffer.GetFrames(out_frame_size) > 0);
352 353 354

		auto frames_written = snd_pcm_writei(pcm, period_buffer.GetHead(),
						     period_buffer.GetFrames(out_frame_size));
355 356
		if (frames_written > 0) {
			written = true;
357 358
			period_buffer.ConsumeFrames(frames_written,
						    out_frame_size);
359
		}
360 361 362 363

		return frames_written;
	}

364
	void LockCaughtError() noexcept {
365 366
		period_buffer.Clear();

367 368
		const std::lock_guard<Mutex> lock(mutex);
		error = std::current_exception();
369
		active = false;
370
		waiting = false;
371
		cond.notify_one();
372 373
	}

374 375 376 377 378 379 380 381 382 383 384 385 386
	/**
	 * Callback for @silence_timer
	 */
	void OnSilenceTimer() noexcept {
		{
			const std::lock_guard<Mutex> lock(mutex);
			assert(active);
			waiting = false;
		}

		MultiSocketMonitor::InvalidateSockets();
	}

387
	/* virtual methods from class MultiSocketMonitor */
388 389
	std::chrono::steady_clock::duration PrepareSockets() noexcept override;
	void DispatchSockets() noexcept override;
Max Kellermann's avatar
Max Kellermann committed
390
};
391

392
static constexpr Domain alsa_output_domain("alsa_output");
393

394
AlsaOutput::AlsaOutput(EventLoop &_loop, const ConfigBlock &block)
395
	:AudioOutput(FLAG_ENABLE_DISABLE),
396 397
	 MultiSocketMonitor(_loop),
	 defer_invalidate_sockets(_loop, BIND_THIS_METHOD(InvalidateSockets)),
398
	 silence_timer(_loop, BIND_THIS_METHOD(OnSilenceTimer)),
399
	 device(block.GetBlockValue("device", "")),
400
#ifdef ENABLE_DSD
401 402 403
	 dop_setting(block.GetBlockValue("dop", false) ||
		     /* legacy name from MPD 0.18 and older: */
		     block.GetBlockValue("dsd_usb", false)),
404
#endif
405 406
	 buffer_time(block.GetPositiveValue("buffer_time",
					    MPD_ALSA_BUFFER_TIME_US)),
407
	 period_time(block.GetPositiveValue("period_time", 0U))
408
{
409
#ifdef SND_PCM_NO_AUTO_RESAMPLE
410
	if (!block.GetBlockValue("auto_resample", true))
411
		mode |= SND_PCM_NO_AUTO_RESAMPLE;
412
#endif
413

414
#ifdef SND_PCM_NO_AUTO_CHANNELS
415
	if (!block.GetBlockValue("auto_channels", true))
416
		mode |= SND_PCM_NO_AUTO_CHANNELS;
417
#endif
418

419
#ifdef SND_PCM_NO_AUTO_FORMAT
420
	if (!block.GetBlockValue("auto_format", true))
421
		mode |= SND_PCM_NO_AUTO_FORMAT;
422
#endif
423 424 425 426 427

	const char *allowed_formats_string =
		block.GetBlockValue("allowed_formats", nullptr);
	if (allowed_formats_string != nullptr)
		allowed_formats = Alsa::AllowedFormat::ParseList(allowed_formats_string);
428 429
}

430
std::map<std::string, std::string>
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
AlsaOutput::GetAttributes() const noexcept
{
	const std::lock_guard<Mutex> lock(attributes_mutex);

	return {
		std::make_pair("allowed_formats",
			       Alsa::ToString(allowed_formats)),
#ifdef ENABLE_DSD
		std::make_pair("dop", dop_setting ? "1" : "0"),
#endif
	};
}

void
AlsaOutput::SetAttribute(std::string &&name, std::string &&value)
{
	if (name == "allowed_formats") {
		const std::lock_guard<Mutex> lock(attributes_mutex);
		allowed_formats = Alsa::AllowedFormat::ParseList({value.data(), value.length()});
#ifdef ENABLE_DSD
	} else if (name == "dop") {
		const std::lock_guard<Mutex> lock(attributes_mutex);
		if (value == "0")
			dop_setting = false;
		else if (value == "1")
			dop_setting = true;
		else
			throw std::invalid_argument("Bad 'dop' value");
#endif
	} else
		AudioOutput::SetAttribute(std::move(name), std::move(value));
}

464
void
465
AlsaOutput::Enable()
466
{
467
	pcm_export.Construct();
468 469
}

470 471
void
AlsaOutput::Disable() noexcept
472
{
473
	pcm_export.Destruct();
474 475
}

Max Kellermann's avatar
Max Kellermann committed
476
static bool
477
alsa_test_default_device()
478
{
Avuton Olrich's avatar
Avuton Olrich committed
479
	snd_pcm_t *handle;
480

481
	int ret = snd_pcm_open(&handle, default_device,
482
			       SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
Avuton Olrich's avatar
Avuton Olrich committed
483
	if (ret) {
484 485 486
		FormatError(alsa_output_domain,
			    "Error opening default ALSA device: %s",
			    snd_strerror(-ret));
487
		return false;
Avuton Olrich's avatar
Avuton Olrich committed
488 489
	} else
		snd_pcm_close(handle);
490

491
	return true;
492 493
}

494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525
/**
 * Wrapper for snd_pcm_sw_params().
 */
static void
AlsaSetupSw(snd_pcm_t *pcm, snd_pcm_uframes_t start_threshold,
	    snd_pcm_uframes_t avail_min)
{
	snd_pcm_sw_params_t *swparams;
	snd_pcm_sw_params_alloca(&swparams);

	int err = snd_pcm_sw_params_current(pcm, swparams);
	if (err < 0)
		throw FormatRuntimeError("snd_pcm_sw_params_current() failed: %s",
					 snd_strerror(-err));

	err = snd_pcm_sw_params_set_start_threshold(pcm, swparams,
						    start_threshold);
	if (err < 0)
		throw FormatRuntimeError("snd_pcm_sw_params_set_start_threshold() failed: %s",
					 snd_strerror(-err));

	err = snd_pcm_sw_params_set_avail_min(pcm, swparams, avail_min);
	if (err < 0)
		throw FormatRuntimeError("snd_pcm_sw_params_set_avail_min() failed: %s",
					 snd_strerror(-err));

	err = snd_pcm_sw_params(pcm, swparams);
	if (err < 0)
		throw FormatRuntimeError("snd_pcm_sw_params() failed: %s",
					 snd_strerror(-err));
}

526 527 528
inline void
AlsaOutput::Setup(AudioFormat &audio_format,
		  PcmExport::Params &params)
529
{
530 531 532
	const auto hw_result = Alsa::SetupHw(pcm,
					     buffer_time, period_time,
					     audio_format, params);
533

534 535 536
	FormatDebug(alsa_output_domain, "format=%s (%s)",
		    snd_pcm_format_name(hw_result.format),
		    snd_pcm_format_description(hw_result.format));
Avuton Olrich's avatar
Avuton Olrich committed
537

538
	FormatDebug(alsa_output_domain, "buffer_size=%u period_size=%u",
539 540 541 542 543
		    (unsigned)hw_result.buffer_size,
		    (unsigned)hw_result.period_size);

	AlsaSetupSw(pcm, hw_result.buffer_size - hw_result.period_size,
		    hw_result.period_size);
544

545
	auto alsa_period_size = hw_result.period_size;
546 547 548 549 550 551 552 553
	if (alsa_period_size == 0)
		/* this works around a SIGFPE bug that occurred when
		   an ALSA driver indicated period_size==0; this
		   caused a division by zero in alsa_play().  By using
		   the fallback "1", we make sure that this won't
		   happen again. */
		alsa_period_size = 1;

554
	period_frames = alsa_period_size;
555
	effective_period_duration = audio_format.FramesToTime<decltype(effective_period_duration)>(period_frames);
556

557
	/* generate silence if there's less than one period of data
558 559 560
	   in the ALSA-PCM buffer */
	max_avail_frames = hw_result.buffer_size - hw_result.period_size;

561
	silence = new uint8_t[snd_pcm_frames_to_bytes(pcm, alsa_period_size)];
562
	snd_pcm_format_set_silence(hw_result.format, silence,
563
				   alsa_period_size * audio_format.channels);
564

565 566
}

567 568
#ifdef ENABLE_DSD

569
inline void
570
AlsaOutput::SetupDop(const AudioFormat audio_format,
571
		     PcmExport::Params &params)
572
{
573
	assert(audio_format.format == SampleFormat::DSD);
574

575
	/* pass 24 bit to AlsaSetup() */
576

577 578
	AudioFormat dop_format = audio_format;
	dop_format.format = SampleFormat::S24_P32;
579

580
	const AudioFormat check = dop_format;
581

582
	Setup(dop_format, params);
583

584
	/* if the device allows only 32 bit, shift all DoP
585 586 587 588
	   samples left by 8 bit and leave the lower 8 bit cleared;
	   the DSD-over-USB documentation does not specify whether
	   this is legal, but there is anecdotical evidence that this
	   is possible (and the only option for some devices) */
589
	params.shift8 = dop_format.format == SampleFormat::S32;
590 591
	if (dop_format.format == SampleFormat::S32)
		dop_format.format = SampleFormat::S24_P32;
592

593
	if (dop_format != check) {
594 595
		/* no bit-perfect playback, which is required
		   for DSD over USB */
596
		delete[] silence;
597
		throw std::runtime_error("Failed to configure DSD-over-PCM");
598 599 600
	}
}

601 602
#endif

603
inline void
604 605 606 607 608
AlsaOutput::SetupOrDop(AudioFormat &audio_format, PcmExport::Params &params
#ifdef ENABLE_DSD
		       , bool dop
#endif
		       )
609
{
610
#ifdef ENABLE_DSD
611 612 613
	std::exception_ptr dop_error;
	if (dop && audio_format.format == SampleFormat::DSD) {
		try {
614
			params.dsd_mode = PcmExport::DsdMode::DOP;
615
			SetupDop(audio_format, params);
616 617 618
			return;
		} catch (...) {
			dop_error = std::current_exception();
619
			params.dsd_mode = PcmExport::DsdMode::NONE;
620
		}
621
	}
622

623 624
	try {
#endif
625
		Setup(audio_format, params);
626
#ifdef ENABLE_DSD
627 628 629 630 631 632 633 634 635
	} catch (...) {
		if (dop_error)
			/* if DoP was attempted, prefer returning the
			   original DoP error instead of the fallback
			   error */
			std::rethrow_exception(dop_error);
		else
			throw;
	}
636
#endif
637 638
}

639 640 641 642 643 644 645 646
static constexpr bool
MaybeDmix(snd_pcm_type_t type)
{
	return type == SND_PCM_TYPE_DMIX || type == SND_PCM_TYPE_PLUG;
}

gcc_pure
static bool
647
MaybeDmix(snd_pcm_t *pcm) noexcept
648 649 650 651
{
	return MaybeDmix(snd_pcm_type(pcm));
}

652 653 654 655 656 657 658 659 660 661 662 663 664
static const Alsa::AllowedFormat &
BestMatch(const std::forward_list<Alsa::AllowedFormat> &haystack,
	  const AudioFormat &needle)
{
	assert(!haystack.empty());

	for (const auto &i : haystack)
		if (needle.MatchMask(i.format))
			return i;

	return haystack.front();
}

665
void
666
AlsaOutput::Open(AudioFormat &audio_format)
667
{
668
#ifdef ENABLE_DSD
669
	bool dop;
670 671
#endif

672 673
	{
		const std::lock_guard<Mutex> lock(attributes_mutex);
674
#ifdef ENABLE_DSD
675
		dop = dop_setting;
676
#endif
677 678 679 680 681 682 683 684 685

		if (!allowed_formats.empty()) {
			const auto &a = BestMatch(allowed_formats,
						  audio_format);
			audio_format.ApplyMask(a.format);
#ifdef ENABLE_DSD
			dop = a.dop;
#endif
		}
686 687
	}

688 689
	int err = snd_pcm_open(&pcm, GetDevice(),
			       SND_PCM_STREAM_PLAYBACK, mode);
690 691 692
	if (err < 0)
		throw FormatRuntimeError("Failed to open ALSA device \"%s\": %s",
					 GetDevice(), snd_strerror(err));
693

694
	FormatDebug(alsa_output_domain, "opened %s type=%s",
695 696
		    snd_pcm_name(pcm),
		    snd_pcm_type_name(snd_pcm_type(pcm)));
697

698 699 700
	PcmExport::Params params;
	params.alsa_channel_order = true;

701
	try {
702 703 704 705 706
		SetupOrDop(audio_format, params
#ifdef ENABLE_DSD
			   , dop
#endif
			   );
707
	} catch (...) {
708
		snd_pcm_close(pcm);
709 710
		std::throw_with_nested(FormatRuntimeError("Error opening ALSA device \"%s\"",
							  GetDevice()));
711 712
	}

713 714 715
	work_around_drain_bug = MaybeDmix(pcm) &&
		GetRuntimeAlsaVersion() < MakeAlsaVersion(1, 1, 4);

716 717
	snd_pcm_nonblock(pcm, 1);

718
#ifdef ENABLE_DSD
719
	if (params.dsd_mode == PcmExport::DsdMode::DOP)
720 721 722
		FormatDebug(alsa_output_domain, "DoP (DSD over PCM) enabled");
#endif

723 724 725 726
	pcm_export->Open(audio_format.format,
			 audio_format.channels,
			 params);

727
	in_frame_size = audio_format.GetFrameSize();
728
	out_frame_size = pcm_export->GetOutputFrameSize();
729

730 731 732 733 734 735 736 737
	drain = false;

	size_t period_size = period_frames * out_frame_size;
	ring_buffer = new boost::lockfree::spsc_queue<uint8_t>(period_size * 4);

	period_buffer.Allocate(period_frames, out_frame_size);

	active = false;
738
	waiting = false;
739
	must_prepare = false;
740
	written = false;
741
	error = {};
742 743
}

744
inline int
745
AlsaOutput::Recover(int err) noexcept
Avuton Olrich's avatar
Avuton Olrich committed
746 747
{
	if (err == -EPIPE) {
748
		FormatDebug(alsa_output_domain,
749 750
			    "Underrun on ALSA device \"%s\"",
			    GetDevice());
Avuton Olrich's avatar
Avuton Olrich committed
751
	} else if (err == -ESTRPIPE) {
752 753
		FormatDebug(alsa_output_domain,
			    "ALSA device \"%s\" was suspended",
754
			    GetDevice());
755 756
	}

757
	switch (snd_pcm_state(pcm)) {
Warren Dukes's avatar
Warren Dukes committed
758
	case SND_PCM_STATE_PAUSED:
759
		err = snd_pcm_pause(pcm, /* disable */ 0);
Warren Dukes's avatar
Warren Dukes committed
760 761
		break;
	case SND_PCM_STATE_SUSPENDED:
762
		err = snd_pcm_resume(pcm);
763 764 765
		if (err == -EAGAIN)
			return 0;
		/* fall-through to snd_pcm_prepare: */
766
#if CLANG_OR_GCC_VERSION(7,0)
767 768
		[[fallthrough]];
#endif
769
	case SND_PCM_STATE_OPEN:
770 771
	case SND_PCM_STATE_SETUP:
	case SND_PCM_STATE_XRUN:
772
		period_buffer.Rewind();
773
		written = false;
774
		err = snd_pcm_prepare(pcm);
Warren Dukes's avatar
Warren Dukes committed
775
		break;
776

777
	case SND_PCM_STATE_DISCONNECTED:
778 779
	case SND_PCM_STATE_DRAINING:
		/* can't play in this state; throw the error */
780
		break;
781

782
	case SND_PCM_STATE_PREPARED:
Max Kellermann's avatar
Max Kellermann committed
783
	case SND_PCM_STATE_RUNNING:
784 785
		/* the state is ok, but the error was unexpected;
		   throw it */
Max Kellermann's avatar
Max Kellermann committed
786
		break;
787 788 789 790 791 792

	default:
		/* this default case is just here to work around
		   -Wswitch due to SND_PCM_STATE_PRIVATE1 (libasound
		   1.1.6) */
		break;
793 794 795 796 797
	}

	return err;
}

798
inline bool
799
AlsaOutput::DrainInternal()
800
{
801 802 803 804
	/* drain ring_buffer */
	CopyRingToPeriodBuffer();

	/* drain period_buffer */
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
	if (!period_buffer.IsCleared()) {
		if (!period_buffer.IsFull())
			/* generate some silence to finish the partial
			   period */
			period_buffer.FillWithSilence(silence, out_frame_size);

		/* drain period_buffer */
		if (!period_buffer.IsDrained()) {
			auto frames_written = WriteFromPeriodBuffer();
			if (frames_written < 0) {
				if (frames_written == -EAGAIN)
					return false;

				throw FormatRuntimeError("snd_pcm_writei() failed: %s",
							 snd_strerror(-frames_written));
			}

			/* need to call CopyRingToPeriodBuffer() and
			   WriteFromPeriodBuffer() again in the next
			   iteration, so don't finish the drain just
			   yet */
			return false;
827
		}
828 829
	}

830 831 832 833 834
	if (!written)
		/* if nothing has ever been written to the PCM, we
		   don't need to drain it */
		return true;

835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
	switch (snd_pcm_state(pcm)) {
	case SND_PCM_STATE_PREPARED:
	case SND_PCM_STATE_RUNNING:
		/* these states require a call to snd_pcm_drain() */
		break;

	case SND_PCM_STATE_DRAINING:
		/* already draining, but not yet finished; this is
		   probably a spurious epoll event, and we should wait
		   for the next one */
		return false;

	default:
		/* all other states cannot be drained, and we're
		   done */
		return true;
	}

853
	/* .. and finally drain the ALSA hardware buffer */
854

855
	int result;
856 857
	if (work_around_drain_bug) {
		snd_pcm_nonblock(pcm, 0);
858
		result = snd_pcm_drain(pcm);
859
		snd_pcm_nonblock(pcm, 1);
860 861
	} else
		result = snd_pcm_drain(pcm);
862

863 864 865 866 867 868 869
	if (result == 0)
		return true;
	else if (result == -EAGAIN)
		return false;
	else
		throw FormatRuntimeError("snd_pcm_drain() failed: %s",
					 snd_strerror(-result));
870
}
871

872
void
873 874
AlsaOutput::Drain()
{
875
	std::unique_lock<Mutex> lock(mutex);
876

877 878 879
	if (error)
		std::rethrow_exception(error);

880 881
	drain = true;

882
	Activate();
883

884
	cond.wait(lock, [this]{ return !drain || !active; });
885 886 887

	if (error)
		std::rethrow_exception(error);
888 889
}

890
inline void
891
AlsaOutput::CancelInternal() noexcept
Avuton Olrich's avatar
Avuton Olrich committed
892
{
893 894 895
	/* this method doesn't need to lock the mutex because while it
	   runs, the calling thread is blocked inside Cancel() */

896
	must_prepare = true;
897

898
	snd_pcm_drop(pcm);
899 900

	pcm_export->Reset();
901
	period_buffer.Clear();
902
	ring_buffer->reset();
903

904
	active = false;
905
	waiting = false;
906 907 908

	MultiSocketMonitor::Reset();
	defer_invalidate_sockets.Cancel();
909
	silence_timer.Cancel();
910 911
}

912 913
void
AlsaOutput::Cancel() noexcept
914
{
915
	if (!LockIsActive()) {
916 917 918 919
		/* early cancel, quick code path without thread
		   synchronization */

		pcm_export->Reset();
920
		assert(period_buffer.IsCleared());
921
		ring_buffer->reset();
922 923 924 925

		return;
	}

926
	BlockingCall(GetEventLoop(), [this](){
927 928
			CancelInternal();
		});
929 930
}

931 932
void
AlsaOutput::Close() noexcept
Avuton Olrich's avatar
Avuton Olrich committed
933
{
934
	/* make sure the I/O thread isn't inside DispatchSockets() */
935
	BlockingCall(GetEventLoop(), [this](){
936
			MultiSocketMonitor::Reset();
937
			defer_invalidate_sockets.Cancel();
938
			silence_timer.Cancel();
939 940 941 942
		});

	period_buffer.Free();
	delete ring_buffer;
943 944
	snd_pcm_close(pcm);
	delete[] silence;
945 946
}

947
size_t
948
AlsaOutput::LockWaitWriteAvailable()
949
{
950 951
	const size_t out_block_size = pcm_export->GetOutputBlockSize();
	const size_t min_available = 2 * out_block_size;
952

953
	std::unique_lock<Mutex> lock(mutex);
954 955

	while (true) {
956 957 958
		if (error)
			std::rethrow_exception(error);

959 960 961 962 963 964 965 966 967
		size_t write_available = ring_buffer->write_available();
		if (write_available >= min_available) {
			/* reserve room for one extra block, just in
			   case PcmExport::Export() has some partial
			   block data in its internal buffer */
			write_available -= out_block_size;

			return write_available / out_frame_size;
		}
968 969 970 971

		/* now that the ring_buffer is full, we can activate
		   the socket handlers to trigger the first
		   snd_pcm_writei() */
972
		if (Activate())
973 974 975 976 977
			/* since everything may have changed while the
			   mutex was unlocked, we need to skip the
			   cond.wait() call below and check the new
			   status */
			continue;
978

979 980
		/* wait for the DispatchSockets() to make room in the
		   ring_buffer */
981
		cond.wait(lock);
982 983
	}
}
984

985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
size_t
AlsaOutput::Play(const void *chunk, size_t size)
{
	assert(size > 0);
	assert(size % in_frame_size == 0);

	const size_t max_frames = LockWaitWriteAvailable();
	const size_t max_size = max_frames * in_frame_size;
	if (size > max_size)
		size = max_size;

	const auto e = pcm_export->Export({chunk, size});
	if (e.empty())
		return size;

	size_t bytes_written = ring_buffer->push((const uint8_t *)e.data,
						 e.size);
	assert(bytes_written == e.size);
	(void)bytes_written;

	return size;
}

1008
std::chrono::steady_clock::duration
1009
AlsaOutput::PrepareSockets() noexcept
1010
{
1011
	if (!LockIsActiveAndNotWaiting()) {
1012 1013
		ClearSocketList();
		return std::chrono::steady_clock::duration(-1);
1014 1015
	}

1016
	try {
1017
		return non_block.PrepareSockets(*this, pcm);
1018 1019 1020 1021 1022
	} catch (...) {
		ClearSocketList();
		LockCaughtError();
		return std::chrono::steady_clock::duration(-1);
	}
1023 1024
}

1025
void
1026
AlsaOutput::DispatchSockets() noexcept
1027
try {
1028 1029
	non_block.DispatchSockets(*this, pcm);

1030 1031
	if (must_prepare) {
		must_prepare = false;
1032
		written = false;
1033 1034 1035 1036 1037 1038 1039

		int err = snd_pcm_prepare(pcm);
		if (err < 0)
			throw FormatRuntimeError("snd_pcm_prepare() failed: %s",
						 snd_strerror(-err));
	}

1040 1041
	{
		const std::lock_guard<Mutex> lock(mutex);
1042 1043 1044

		assert(active);

1045 1046 1047 1048 1049 1050 1051 1052 1053 1054
		if (drain) {
			{
				ScopeUnlock unlock(mutex);
				if (!DrainInternal())
					return;

				MultiSocketMonitor::InvalidateSockets();
			}

			drain = false;
1055
			cond.notify_one();
1056 1057 1058
			return;
		}
	}
1059

1060 1061
	CopyRingToPeriodBuffer();

1062
	if (!period_buffer.IsFull()) {
1063 1064
		if (snd_pcm_state(pcm) == SND_PCM_STATE_PREPARED ||
		    snd_pcm_avail(pcm) <= max_avail_frames) {
1065 1066 1067 1068 1069 1070 1071 1072 1073
			/* at SND_PCM_STATE_PREPARED (not yet switched
			   to SND_PCM_STATE_RUNNING), we have no
			   pressure to fill the ALSA buffer, because
			   no xrun can possibly occur; and if no data
			   is available right now, we can easily wait
			   until some is available; so we just stop
			   monitoring the ALSA file descriptor, and
			   let it be reactivated by Play()/Activate()
			   whenever more data arrives */
1074 1075
			/* the same applies when there is still enough
			   data in the ALSA-PCM buffer (determined by
1076
			   snd_pcm_avail()); this can happen at the
1077 1078
			   start of playback, when our ring_buffer is
			   smaller than the ALSA-PCM buffer */
1079 1080 1081

			{
				const std::lock_guard<Mutex> lock(mutex);
1082
				waiting = true;
1083
				cond.notify_one();
1084 1085 1086 1087
			}

			/* avoid race condition: see if data has
			   arrived meanwhile before disabling the
1088
			   event (but after setting the "waiting"
1089 1090 1091 1092
			   flag) */
			if (!CopyRingToPeriodBuffer()) {
				MultiSocketMonitor::Reset();
				defer_invalidate_sockets.Cancel();
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103

				/* just in case Play() doesn't get
				   called soon enough, schedule a
				   timer which generates silence
				   before the xrun occurs */
				/* the timer fires in half of a
				   period; this short duration may
				   produce a few more wakeups than
				   necessary, but should be small
				   enough to avoid the xrun */
				silence_timer.Schedule(effective_period_duration / 2);
1104 1105 1106 1107 1108
			}

			return;
		}

1109 1110 1111
		if (throttle_silence_log.CheckUpdate(std::chrono::seconds(5)))
			FormatWarning(alsa_output_domain, "Decoder is too slow; playing silence to avoid xrun");

1112 1113 1114
		/* insert some silence if the buffer has not enough
		   data yet, to avoid ALSA xrun */
		period_buffer.FillWithSilence(silence, out_frame_size);
1115
	}
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131

	auto frames_written = WriteFromPeriodBuffer();
	if (frames_written < 0) {
		if (frames_written == -EAGAIN || frames_written == -EINTR)
			/* try again in the next DispatchSockets()
			   call which is still scheduled */
			return;

		if (Recover(frames_written) < 0)
			throw FormatRuntimeError("snd_pcm_writei() failed: %s",
						 snd_strerror(-frames_written));

		/* recovered; try again in the next DispatchSockets()
		   call */
		return;
	}
1132
} catch (...) {
1133
	MultiSocketMonitor::Reset();
1134
	LockCaughtError();
1135 1136
}

1137
const struct AudioOutputPlugin alsa_output_plugin = {
1138 1139
	"alsa",
	alsa_test_default_device,
1140
	&AlsaOutput::Create,
1141
	&alsa_mixer_plugin,
1142
};