AlsaOutputPlugin.cxx 24.3 KB
Newer Older
1
/*
2
 * Copyright 2003-2018 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/PcmExport.hxx"
30
#include "thread/Mutex.hxx"
31
#include "thread/Cond.hxx"
32
#include "util/Manual.hxx"
33
#include "util/RuntimeError.hxx"
34
#include "util/Domain.hxx"
35
#include "util/ConstBuffer.hxx"
36
#include "util/ScopeExit.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
	Manual<PcmExport> pcm_export;
60

61 62 63 64
	/**
	 * The configured name of the ALSA device; empty for the
	 * default device
	 */
65
	const std::string device;
66

67
#ifdef ENABLE_DSD
68
	/**
Max Kellermann's avatar
Max Kellermann committed
69
	 * Enable DSD over PCM according to the DoP standard?
70
	 *
71
	 * @see http://dsd-guide.com/dop-open-standard
72
	 */
73
	bool dop_setting;
74
#endif
75

Max Kellermann's avatar
Max Kellermann committed
76
	/** libasound's buffer_time setting (in microseconds) */
77
	const unsigned buffer_time;
Max Kellermann's avatar
Max Kellermann committed
78 79

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

82
	/** the mode flags passed to snd_pcm_open */
83
	int mode = 0;
84

85 86
	std::forward_list<Alsa::AllowedFormat> allowed_formats;

87 88 89 90 91
	/**
	 * Protects #dop_setting and #allowed_formats.
	 */
	mutable Mutex attributes_mutex;

Max Kellermann's avatar
Max Kellermann committed
92
	/** the libasound PCM device handle */
Max Kellermann's avatar
Max Kellermann committed
93
	snd_pcm_t *pcm;
Max Kellermann's avatar
Max Kellermann committed
94

95
#ifndef NDEBUG
96 97 98 99
	/**
	 * The size of one audio frame passed to method play().
	 */
	size_t in_frame_size;
100
#endif
101 102 103 104 105

	/**
	 * The size of one audio frame passed to libasound.
	 */
	size_t out_frame_size;
106 107 108 109 110 111

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

112 113 114 115 116 117 118
	/**
	 * 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;

119 120 121 122 123 124 125 126 127 128 129
	/**
	 * 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;

130
	/**
131 132
	 * After Open(), has this output been activated by a Play()
	 * command?
133
	 *
134
	 * Protected by #mutex.
135
	 */
136
	bool active;
137

138
	/**
139 140 141 142 143 144 145 146
	 * 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.
147
	 */
148
	bool must_prepare;
149

150 151 152 153 154 155 156 157 158 159
	/**
	 * 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;

160 161
	bool drain;

162 163 164 165 166
	/**
	 * This buffer gets allocated after opening the ALSA device.
	 * It contains silence samples, enough to fill one period (see
	 * #period_frames).
	 */
167
	uint8_t *silence;
168

169
	AlsaNonBlockPcm non_block;
170 171 172 173 174 175

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

176
	Alsa::PeriodBuffer period_buffer;
177 178

	/**
179
	 * Protects #cond, #error, #active, #drain.
180 181 182 183 184 185 186 187 188 189 190 191
	 */
	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;

192
public:
193
	AlsaOutput(EventLoop &loop, const ConfigBlock &block);
194

195
	~AlsaOutput() noexcept {
196 197 198 199
		/* free libasound's config cache */
		snd_config_update_free_global();
	}

200 201
	using MultiSocketMonitor::GetEventLoop;

202
	gcc_pure
203
	const char *GetDevice() const noexcept {
204 205 206
		return device.empty() ? default_device : device.c_str();
	}

207 208 209 210
	static AudioOutput *Create(EventLoop &event_loop,
				   const ConfigBlock &block) {
		return new AlsaOutput(event_loop, block);
	}
211

212
private:
213 214 215
	const std::map<std::string, std::string> GetAttributes() const noexcept override;
	void SetAttribute(std::string &&name, std::string &&value) override;

216 217
	void Enable() override;
	void Disable() noexcept override;
218

219 220
	void Open(AudioFormat &audio_format) override;
	void Close() noexcept override;
221

222 223 224
	size_t Play(const void *chunk, size_t size) override;
	void Drain() override;
	void Cancel() noexcept override;
225

226 227 228 229 230 231 232 233
	/**
	 * Set up the snd_pcm_t object which was opened by the caller.
	 * Set up the configured settings and the audio format.
	 *
	 * Throws #std::runtime_error on error.
	 */
	void Setup(AudioFormat &audio_format, PcmExport::Params &params);

234
#ifdef ENABLE_DSD
235 236
	void SetupDop(AudioFormat audio_format,
		      PcmExport::Params &params);
237 238
#endif

239 240 241 242 243
	void SetupOrDop(AudioFormat &audio_format, PcmExport::Params &params
#ifdef ENABLE_DSD
			, bool dop
#endif
			);
244

245 246 247 248 249 250
	gcc_pure
	bool LockIsActive() const noexcept {
		const std::lock_guard<Mutex> lock(mutex);
		return active;
	}

251 252 253 254 255
	/**
	 * 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.
256 257
	 *
	 * Caller must hold the mutex.
258 259 260
	 *
	 * @return true if Activate() was called, false if the mutex
	 * was never unlocked
261
	 */
262
	bool Activate() noexcept {
263
		if (active)
264
			return false;
265

266 267
		active = true;

268
		const ScopeUnlock unlock(mutex);
269
		defer_invalidate_sockets.Schedule();
270
		return true;
271 272
	}

273
	int Recover(int err) noexcept;
274 275

	/**
276 277
	 * Drain all buffers.  To be run in #EventLoop's thread.
	 *
278 279
	 * Throws on error.
	 *
280 281
	 * @return true if draining is complete, false if this method
	 * needs to be called again later
282
	 */
283
	bool DrainInternal();
284 285 286 287 288

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

291 292 293 294
	/**
	 * @return false if no data was moved
	 */
	bool CopyRingToPeriodBuffer() noexcept {
295
		if (period_buffer.IsFull())
296
			return false;
297 298 299 300

		size_t nbytes = ring_buffer->pop(period_buffer.GetTail(),
						 period_buffer.GetSpaceBytes());
		if (nbytes == 0)
301
			return false;
302 303 304 305 306 307

		period_buffer.AppendBytes(nbytes);

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

		return true;
311 312
	}

313
	snd_pcm_sframes_t WriteFromPeriodBuffer() noexcept {
314 315 316 317
		assert(!period_buffer.IsEmpty());

		auto frames_written = snd_pcm_writei(pcm, period_buffer.GetHead(),
						     period_buffer.GetFrames(out_frame_size));
318 319
		if (frames_written > 0) {
			written = true;
320 321
			period_buffer.ConsumeFrames(frames_written,
						    out_frame_size);
322
		}
323 324 325 326

		return frames_written;
	}

327
	void LockCaughtError() noexcept {
328 329
		period_buffer.Clear();

330 331
		const std::lock_guard<Mutex> lock(mutex);
		error = std::current_exception();
332
		active = false;
333
		cond.notify_one();
334 335
	}

336
	/* virtual methods from class MultiSocketMonitor */
337 338
	std::chrono::steady_clock::duration PrepareSockets() noexcept override;
	void DispatchSockets() noexcept override;
Max Kellermann's avatar
Max Kellermann committed
339
};
340

341
static constexpr Domain alsa_output_domain("alsa_output");
342

343
AlsaOutput::AlsaOutput(EventLoop &_loop, const ConfigBlock &block)
344
	:AudioOutput(FLAG_ENABLE_DISABLE),
345 346
	 MultiSocketMonitor(_loop),
	 defer_invalidate_sockets(_loop, BIND_THIS_METHOD(InvalidateSockets)),
347
	 device(block.GetBlockValue("device", "")),
348
#ifdef ENABLE_DSD
349 350 351
	 dop_setting(block.GetBlockValue("dop", false) ||
		     /* legacy name from MPD 0.18 and older: */
		     block.GetBlockValue("dsd_usb", false)),
352
#endif
353 354 355
	 buffer_time(block.GetPositiveValue("buffer_time",
					    MPD_ALSA_BUFFER_TIME_US)),
	 period_time(block.GetPositiveValue("period_time", 0u))
356
{
357
#ifdef SND_PCM_NO_AUTO_RESAMPLE
358
	if (!block.GetBlockValue("auto_resample", true))
359
		mode |= SND_PCM_NO_AUTO_RESAMPLE;
360
#endif
361

362
#ifdef SND_PCM_NO_AUTO_CHANNELS
363
	if (!block.GetBlockValue("auto_channels", true))
364
		mode |= SND_PCM_NO_AUTO_CHANNELS;
365
#endif
366

367
#ifdef SND_PCM_NO_AUTO_FORMAT
368
	if (!block.GetBlockValue("auto_format", true))
369
		mode |= SND_PCM_NO_AUTO_FORMAT;
370
#endif
371 372 373 374 375

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

378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
const std::map<std::string, std::string>
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));
}

412
void
413
AlsaOutput::Enable()
414
{
415
	pcm_export.Construct();
416 417
}

418 419
void
AlsaOutput::Disable() noexcept
420
{
421
	pcm_export.Destruct();
422 423
}

Max Kellermann's avatar
Max Kellermann committed
424
static bool
425
alsa_test_default_device()
426
{
Avuton Olrich's avatar
Avuton Olrich committed
427
	snd_pcm_t *handle;
428

429
	int ret = snd_pcm_open(&handle, default_device,
430
			       SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
Avuton Olrich's avatar
Avuton Olrich committed
431
	if (ret) {
432 433 434
		FormatError(alsa_output_domain,
			    "Error opening default ALSA device: %s",
			    snd_strerror(-ret));
435
		return false;
Avuton Olrich's avatar
Avuton Olrich committed
436 437
	} else
		snd_pcm_close(handle);
438

439
	return true;
440 441
}

442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
/**
 * 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));
}

474 475 476
inline void
AlsaOutput::Setup(AudioFormat &audio_format,
		  PcmExport::Params &params)
477
{
478 479 480
	const auto hw_result = Alsa::SetupHw(pcm,
					     buffer_time, period_time,
					     audio_format, params);
481

482 483 484
	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
485

486
	FormatDebug(alsa_output_domain, "buffer_size=%u period_size=%u",
487 488 489 490 491
		    (unsigned)hw_result.buffer_size,
		    (unsigned)hw_result.period_size);

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

493
	auto alsa_period_size = hw_result.period_size;
494 495 496 497 498 499 500 501
	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;

502
	period_frames = alsa_period_size;
503

504 505 506 507
	/* generate silence if there's less than once period of data
	   in the ALSA-PCM buffer */
	max_avail_frames = hw_result.buffer_size - hw_result.period_size;

508
	silence = new uint8_t[snd_pcm_frames_to_bytes(pcm, alsa_period_size)];
509
	snd_pcm_format_set_silence(hw_result.format, silence,
510
				   alsa_period_size * audio_format.channels);
511

512 513
}

514 515
#ifdef ENABLE_DSD

516
inline void
517
AlsaOutput::SetupDop(const AudioFormat audio_format,
518
		     PcmExport::Params &params)
519
{
520
	assert(audio_format.format == SampleFormat::DSD);
521

522
	/* pass 24 bit to AlsaSetup() */
523

524 525
	AudioFormat dop_format = audio_format;
	dop_format.format = SampleFormat::S24_P32;
526

527
	const AudioFormat check = dop_format;
528

529
	Setup(dop_format, params);
530

531
	/* if the device allows only 32 bit, shift all DoP
532 533 534 535
	   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) */
536
	params.shift8 = dop_format.format == SampleFormat::S32;
537 538
	if (dop_format.format == SampleFormat::S32)
		dop_format.format = SampleFormat::S24_P32;
539

540
	if (dop_format != check) {
541 542
		/* no bit-perfect playback, which is required
		   for DSD over USB */
543
		delete[] silence;
544
		throw std::runtime_error("Failed to configure DSD-over-PCM");
545 546 547
	}
}

548 549
#endif

550
inline void
551 552 553 554 555
AlsaOutput::SetupOrDop(AudioFormat &audio_format, PcmExport::Params &params
#ifdef ENABLE_DSD
		       , bool dop
#endif
		       )
556
{
557
#ifdef ENABLE_DSD
558 559 560 561
	std::exception_ptr dop_error;
	if (dop && audio_format.format == SampleFormat::DSD) {
		try {
			params.dop = true;
562
			SetupDop(audio_format, params);
563 564 565
			return;
		} catch (...) {
			dop_error = std::current_exception();
566
			params.dop = false;
567
		}
568
	}
569

570 571
	try {
#endif
572
		Setup(audio_format, params);
573
#ifdef ENABLE_DSD
574 575 576 577 578 579 580 581 582
	} 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;
	}
583
#endif
584 585
}

586 587 588 589 590 591 592 593
static constexpr bool
MaybeDmix(snd_pcm_type_t type)
{
	return type == SND_PCM_TYPE_DMIX || type == SND_PCM_TYPE_PLUG;
}

gcc_pure
static bool
594
MaybeDmix(snd_pcm_t *pcm) noexcept
595 596 597 598
{
	return MaybeDmix(snd_pcm_type(pcm));
}

599 600 601 602 603 604 605 606 607 608 609 610 611
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();
}

612
void
613
AlsaOutput::Open(AudioFormat &audio_format)
614
{
615
#ifdef ENABLE_DSD
616
	bool dop;
617 618
#endif

619 620
	{
		const std::lock_guard<Mutex> lock(attributes_mutex);
621
#ifdef ENABLE_DSD
622
		dop = dop_setting;
623
#endif
624 625 626 627 628 629 630 631 632

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

635 636
	int err = snd_pcm_open(&pcm, GetDevice(),
			       SND_PCM_STREAM_PLAYBACK, mode);
637 638 639
	if (err < 0)
		throw FormatRuntimeError("Failed to open ALSA device \"%s\": %s",
					 GetDevice(), snd_strerror(err));
640

641
	FormatDebug(alsa_output_domain, "opened %s type=%s",
642 643
		    snd_pcm_name(pcm),
		    snd_pcm_type_name(snd_pcm_type(pcm)));
644

645 646 647
	PcmExport::Params params;
	params.alsa_channel_order = true;

648
	try {
649 650 651 652 653
		SetupOrDop(audio_format, params
#ifdef ENABLE_DSD
			   , dop
#endif
			   );
654
	} catch (...) {
655
		snd_pcm_close(pcm);
656 657
		std::throw_with_nested(FormatRuntimeError("Error opening ALSA device \"%s\"",
							  GetDevice()));
658 659
	}

660 661 662
	work_around_drain_bug = MaybeDmix(pcm) &&
		GetRuntimeAlsaVersion() < MakeAlsaVersion(1, 1, 4);

663 664
	snd_pcm_nonblock(pcm, 1);

665 666 667 668 669
#ifdef ENABLE_DSD
	if (params.dop)
		FormatDebug(alsa_output_domain, "DoP (DSD over PCM) enabled");
#endif

670 671 672 673
	pcm_export->Open(audio_format.format,
			 audio_format.channels,
			 params);

674
#ifndef NDEBUG
675
	in_frame_size = audio_format.GetFrameSize();
676
#endif
677
	out_frame_size = pcm_export->GetFrameSize(audio_format);
678

679 680 681 682 683 684 685 686
	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;
687
	must_prepare = false;
688
	written = false;
689
	error = {};
690 691
}

692
inline int
693
AlsaOutput::Recover(int err) noexcept
Avuton Olrich's avatar
Avuton Olrich committed
694 695
{
	if (err == -EPIPE) {
696
		FormatDebug(alsa_output_domain,
697 698
			    "Underrun on ALSA device \"%s\"",
			    GetDevice());
Avuton Olrich's avatar
Avuton Olrich committed
699
	} else if (err == -ESTRPIPE) {
700 701
		FormatDebug(alsa_output_domain,
			    "ALSA device \"%s\" was suspended",
702
			    GetDevice());
703 704
	}

705
	switch (snd_pcm_state(pcm)) {
Warren Dukes's avatar
Warren Dukes committed
706
	case SND_PCM_STATE_PAUSED:
707
		err = snd_pcm_pause(pcm, /* disable */ 0);
Warren Dukes's avatar
Warren Dukes committed
708 709
		break;
	case SND_PCM_STATE_SUSPENDED:
710
		err = snd_pcm_resume(pcm);
711 712 713
		if (err == -EAGAIN)
			return 0;
		/* fall-through to snd_pcm_prepare: */
714 715 716
#if GCC_CHECK_VERSION(7,0)
		[[fallthrough]];
#endif
717
	case SND_PCM_STATE_OPEN:
718 719
	case SND_PCM_STATE_SETUP:
	case SND_PCM_STATE_XRUN:
720
		period_buffer.Rewind();
721
		written = false;
722
		err = snd_pcm_prepare(pcm);
Warren Dukes's avatar
Warren Dukes committed
723
		break;
724 725
	case SND_PCM_STATE_DISCONNECTED:
		break;
Max Kellermann's avatar
Max Kellermann committed
726
	/* this is no error, so just keep running */
727
	case SND_PCM_STATE_PREPARED:
Max Kellermann's avatar
Max Kellermann committed
728
	case SND_PCM_STATE_RUNNING:
729
	case SND_PCM_STATE_DRAINING:
Max Kellermann's avatar
Max Kellermann committed
730 731
		err = 0;
		break;
732 733 734 735 736 737

	default:
		/* this default case is just here to work around
		   -Wswitch due to SND_PCM_STATE_PRIVATE1 (libasound
		   1.1.6) */
		break;
738 739 740 741 742
	}

	return err;
}

743
inline bool
744
AlsaOutput::DrainInternal()
745
{
746 747 748 749 750
	/* drain ring_buffer */
	CopyRingToPeriodBuffer();

	auto period_position = period_buffer.GetPeriodPosition(out_frame_size);
	if (period_position > 0)
751 752
		/* generate some silence to finish the partial
		   period */
753 754 755 756 757
		period_buffer.FillWithSilence(silence, out_frame_size);

	/* drain period_buffer */
	if (!period_buffer.IsEmpty()) {
		auto frames_written = WriteFromPeriodBuffer();
758 759 760 761 762 763
		if (frames_written < 0) {
			if (frames_written == -EAGAIN)
				return false;

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

766 767 768 769
		/* need to call CopyRingToPeriodBuffer() and
		   WriteFromPeriodBuffer() again in the next
		   iteration, so don't finish the drain just yet */
		return period_buffer.IsEmpty();
770 771
	}

772 773 774 775 776
	if (!written)
		/* if nothing has ever been written to the PCM, we
		   don't need to drain it */
		return true;

777
	/* .. and finally drain the ALSA hardware buffer */
778

779
	int result;
780 781
	if (work_around_drain_bug) {
		snd_pcm_nonblock(pcm, 0);
782
		result = snd_pcm_drain(pcm);
783
		snd_pcm_nonblock(pcm, 1);
784 785
	} else
		result = snd_pcm_drain(pcm);
786

787 788 789 790 791 792 793
	if (result == 0)
		return true;
	else if (result == -EAGAIN)
		return false;
	else
		throw FormatRuntimeError("snd_pcm_drain() failed: %s",
					 snd_strerror(-result));
794
}
795

796
void
797 798
AlsaOutput::Drain()
{
799
	std::unique_lock<Mutex> lock(mutex);
800

801 802 803
	if (error)
		std::rethrow_exception(error);

804 805
	drain = true;

806
	Activate();
807

808
	cond.wait(lock, [this]{ return !drain || !active; });
809 810 811

	if (error)
		std::rethrow_exception(error);
812 813
}

814
inline void
815
AlsaOutput::CancelInternal() noexcept
Avuton Olrich's avatar
Avuton Olrich committed
816
{
817 818 819
	/* this method doesn't need to lock the mutex because while it
	   runs, the calling thread is blocked inside Cancel() */

820
	must_prepare = true;
821

822
	snd_pcm_drop(pcm);
823 824

	pcm_export->Reset();
825
	period_buffer.Clear();
826
	ring_buffer->reset();
827

828
	active = false;
829 830 831

	MultiSocketMonitor::Reset();
	defer_invalidate_sockets.Cancel();
832 833
}

834 835
void
AlsaOutput::Cancel() noexcept
836
{
837
	if (!LockIsActive()) {
838 839 840 841 842
		/* early cancel, quick code path without thread
		   synchronization */

		pcm_export->Reset();
		assert(period_buffer.IsEmpty());
843
		ring_buffer->reset();
844 845 846 847

		return;
	}

848
	BlockingCall(GetEventLoop(), [this](){
849 850
			CancelInternal();
		});
851 852
}

853 854
void
AlsaOutput::Close() noexcept
Avuton Olrich's avatar
Avuton Olrich committed
855
{
856
	/* make sure the I/O thread isn't inside DispatchSockets() */
857
	BlockingCall(GetEventLoop(), [this](){
858
			MultiSocketMonitor::Reset();
859
			defer_invalidate_sockets.Cancel();
860 861 862 863
		});

	period_buffer.Free();
	delete ring_buffer;
864 865
	snd_pcm_close(pcm);
	delete[] silence;
866 867
}

868
size_t
869
AlsaOutput::Play(const void *chunk, size_t size)
870
{
871 872
	assert(size > 0);
	assert(size % in_frame_size == 0);
873

874 875 876 877 878 879 880 881 882
	const auto e = pcm_export->Export({chunk, size});
	if (e.size == 0)
		/* the DoP (DSD over PCM) filter converts two frames
		   at a time and ignores the last odd frame; if there
		   was only one frame (e.g. the last frame in the
		   file), the result is empty; to avoid an endless
		   loop, bail out here, and pretend the one frame has
		   been played */
		return size;
883

884
	std::unique_lock<Mutex> lock(mutex);
885 886

	while (true) {
887 888 889
		if (error)
			std::rethrow_exception(error);

890 891
		size_t bytes_written = ring_buffer->push((const uint8_t *)e.data,
							 e.size);
892 893 894 895 896 897
		if (bytes_written > 0)
			return pcm_export->CalcSourceSize(bytes_written);

		/* now that the ring_buffer is full, we can activate
		   the socket handlers to trigger the first
		   snd_pcm_writei() */
898
		if (Activate())
899 900 901 902 903
			/* 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;
904

905 906
		/* wait for the DispatchSockets() to make room in the
		   ring_buffer */
907
		cond.wait(lock);
908 909
	}
}
910

911
std::chrono::steady_clock::duration
912
AlsaOutput::PrepareSockets() noexcept
913
{
914
	if (!LockIsActive()) {
915 916
		ClearSocketList();
		return std::chrono::steady_clock::duration(-1);
917 918
	}

919
	try {
920
		return non_block.PrepareSockets(*this, pcm);
921 922 923 924 925
	} catch (...) {
		ClearSocketList();
		LockCaughtError();
		return std::chrono::steady_clock::duration(-1);
	}
926 927
}

928
void
929
AlsaOutput::DispatchSockets() noexcept
930
try {
931 932
	non_block.DispatchSockets(*this, pcm);

933 934
	if (must_prepare) {
		must_prepare = false;
935
		written = false;
936 937 938 939 940 941 942

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

943 944
	{
		const std::lock_guard<Mutex> lock(mutex);
945 946 947

		assert(active);

948 949 950 951 952 953 954 955 956 957
		if (drain) {
			{
				ScopeUnlock unlock(mutex);
				if (!DrainInternal())
					return;

				MultiSocketMonitor::InvalidateSockets();
			}

			drain = false;
958
			cond.notify_one();
959 960 961
			return;
		}
	}
962

963 964
	CopyRingToPeriodBuffer();

965
	if (period_buffer.IsEmpty()) {
966 967
		if (snd_pcm_state(pcm) == SND_PCM_STATE_PREPARED ||
		    snd_pcm_avail(pcm) <= max_avail_frames) {
968 969 970 971 972 973 974 975 976
			/* 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 */
977 978 979 980 981
			/* the same applies when there is still enough
			   data in the ALSA-PCM buffer (determined by
			   snd_pcm_avail()); this can happend at the
			   start of playback, when our ring_buffer is
			   smaller than the ALSA-PCM buffer */
982 983 984 985

			{
				const std::lock_guard<Mutex> lock(mutex);
				active = false;
986
				cond.notify_one();
987 988 989 990 991 992 993 994 995 996 997 998 999 1000
			}

			/* avoid race condition: see if data has
			   arrived meanwhile before disabling the
			   event (but after clearing the "active"
			   flag) */
			if (!CopyRingToPeriodBuffer()) {
				MultiSocketMonitor::Reset();
				defer_invalidate_sockets.Cancel();
			}

			return;
		}

1001 1002 1003
		/* insert some silence if the buffer has not enough
		   data yet, to avoid ALSA xrun */
		period_buffer.FillWithSilence(silence, out_frame_size);
1004
	}
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020

	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;
	}
1021
} catch (...) {
1022
	MultiSocketMonitor::Reset();
1023
	LockCaughtError();
1024 1025
}

1026
const struct AudioOutputPlugin alsa_output_plugin = {
1027 1028
	"alsa",
	alsa_test_default_device,
1029
	&AlsaOutput::Create,
1030
	&alsa_mixer_plugin,
1031
};