PulseOutputPlugin.cxx 18.7 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 "PulseOutputPlugin.hxx"
21
#include "lib/pulse/Domain.hxx"
22
#include "lib/pulse/Error.hxx"
23
#include "lib/pulse/LogError.hxx"
24
#include "lib/pulse/LockGuard.hxx"
25
#include "../OutputAPI.hxx"
Max Kellermann's avatar
Max Kellermann committed
26 27
#include "mixer/MixerList.hxx"
#include "mixer/plugins/PulseMixerPlugin.hxx"
28
#include "util/ScopeExit.hxx"
29
#include "Log.hxx"
30

31 32 33
#include <pulse/thread-mainloop.h>
#include <pulse/context.h>
#include <pulse/stream.h>
34 35
#include <pulse/introspect.h>
#include <pulse/subscribe.h>
36
#include <pulse/version.h>
37

38 39
#include <stdexcept>

40
#include <assert.h>
41
#include <stddef.h>
42
#include <stdlib.h>
43

44
#define MPD_PULSE_NAME "Music Player Daemon"
45

46
class PulseOutput final : AudioOutput {
47 48 49 50
	const char *name;
	const char *server;
	const char *sink;

51
	PulseMixer *mixer = nullptr;
52

53
	struct pa_threaded_mainloop *mainloop = nullptr;
54
	struct pa_context *context;
55
	struct pa_stream *stream = nullptr;
56 57

	size_t writable;
58

59 60
	bool pause;

61
	explicit PulseOutput(const ConfigBlock &block);
62

63 64 65 66 67 68 69 70 71
public:
	void SetMixer(PulseMixer &_mixer);

	void ClearMixer(gcc_unused PulseMixer &old_mixer) {
		assert(mixer == &old_mixer);

		mixer = nullptr;
	}

72
	void SetVolume(const pa_cvolume &volume);
73

74 75
	struct pa_threaded_mainloop *GetMainloop() {
		return mainloop;
76 77 78 79 80 81 82 83 84 85 86
	}

	void OnContextStateChanged(pa_context_state_t new_state);
	void OnServerLayoutChanged(pa_subscription_event_type_t t,
				   uint32_t idx);
	void OnStreamSuspended(pa_stream *_stream);
	void OnStreamStateChanged(pa_stream *_stream,
				  pa_stream_state_t new_state);
	void OnStreamWrite(size_t nbytes);

	void OnStreamSuccess() {
87
		Signal();
88 89
	}

90 91
	static bool TestDefaultDevice();

92 93 94 95
	static AudioOutput *Create(EventLoop &,
				   const ConfigBlock &block) {
		return new PulseOutput(block);
	}
96

97 98
	void Enable() override;
	void Disable() noexcept override;
99

100 101
	void Open(AudioFormat &audio_format) override;
	void Close() noexcept override;
102

103 104 105
	std::chrono::steady_clock::duration Delay() const noexcept override;
	size_t Play(const void *chunk, size_t size) override;
	void Cancel() noexcept override;
106
	bool Pause() override;
107 108 109 110 111

private:
	/**
	 * Attempt to connect asynchronously to the PulseAudio server.
	 *
112
	 * Throws #std::runtime_error on error.
113
	 */
114
	void Connect();
115 116 117 118 119 120

	/**
	 * Create, set up and connect a context.
	 *
	 * Caller must lock the main loop.
	 *
121
	 * Throws #std::runtime_error on error.
122
	 */
123
	void SetupContext();
124 125 126 127 128 129 130 131

	/**
	 * Frees and clears the context.
	 *
	 * Caller must lock the main loop.
	 */
	void DeleteContext();

132 133 134 135
	void Signal() {
		pa_threaded_mainloop_signal(mainloop, 0);
	}

136 137 138 139 140 141 142
	/**
	 * Check if the context is (already) connected, and waits if
	 * not.  If the context has been disconnected, retry to
	 * connect.
	 *
	 * Caller must lock the main loop.
	 *
143
	 * Throws #std::runtime_error on error.
144
	 */
145
	void WaitConnection();
146 147 148 149 150 151

	/**
	 * Create, set up and connect a context.
	 *
	 * Caller must lock the main loop.
	 *
152
	 * Throws #std::runtime_error on error.
153
	 */
154
	void SetupStream(const pa_sample_spec &ss);
155 156 157 158 159 160 161 162 163 164 165

	/**
	 * Frees and clears the stream.
	 */
	void DeleteStream();

	/**
	 * Check if the stream is (already) connected, and waits if
	 * not.  The mainloop must be locked before calling this
	 * function.
	 *
166
	 * Throws #std::runtime_error on error.
167
	 */
168
	void WaitStream();
169 170 171

	/**
	 * Sets cork mode on the stream.
172 173
	 *
	 * Throws #std::runtime_error on error.
174
	 */
175
	void StreamPause(bool pause);
176 177
};

178
PulseOutput::PulseOutput(const ConfigBlock &block)
179
	:AudioOutput(FLAG_ENABLE_DISABLE|FLAG_PAUSE),
180 181 182 183 184 185 186 187
	 name(block.GetBlockValue("name", "mpd_pulse")),
	 server(block.GetBlockValue("server")),
	 sink(block.GetBlockValue("sink"))
{
	setenv("PULSE_PROP_media.role", "music", true);
	setenv("PULSE_PROP_application.icon_name", "mpd", true);
}

188 189
struct pa_threaded_mainloop *
pulse_output_get_mainloop(PulseOutput &po)
190
{
191
	return po.GetMainloop();
192 193
}

194 195
inline void
PulseOutput::SetMixer(PulseMixer &_mixer)
196
{
197
	assert(mixer == nullptr);
198

199
	mixer = &_mixer;
200

201
	if (mainloop == nullptr)
202 203
		return;

204
	Pulse::LockGuard lock(mainloop);
205

206 207 208
	if (context != nullptr &&
	    pa_context_get_state(context) == PA_CONTEXT_READY) {
		pulse_mixer_on_connect(_mixer, context);
209

210 211 212
		if (stream != nullptr &&
		    pa_stream_get_state(stream) == PA_STREAM_READY)
			pulse_mixer_on_change(_mixer, context, stream);
213 214 215 216
	}
}

void
217
pulse_output_set_mixer(PulseOutput &po, PulseMixer &pm)
218
{
219
	po.SetMixer(pm);
220 221
}

222 223
void
pulse_output_clear_mixer(PulseOutput &po, PulseMixer &pm)
224
{
225 226
	po.ClearMixer(pm);
}
227

228 229
inline void
PulseOutput::SetVolume(const pa_cvolume &volume)
230 231
{
	if (context == nullptr || stream == nullptr ||
232 233
	    pa_stream_get_state(stream) != PA_STREAM_READY)
		throw std::runtime_error("disconnected");
234

235 236 237 238
	pa_operation *o =
		pa_context_set_sink_input_volume(context,
						 pa_stream_get_index(stream),
						 &volume, nullptr, nullptr);
239 240
	if (o == nullptr)
		throw std::runtime_error("failed to set PulseAudio volume");
241 242 243 244

	pa_operation_unref(o);
}

245 246
void
pulse_output_set_volume(PulseOutput &po, const pa_cvolume *volume)
247
{
248
	return po.SetVolume(*volume);
249 250
}

251 252 253 254 255 256 257 258 259 260 261
/**
 * \brief waits for a pulseaudio operation to finish, frees it and
 *     unlocks the mainloop
 * \param operation the operation to wait for
 * \return true if operation has finished normally (DONE state),
 *     false otherwise
 */
static bool
pulse_wait_for_operation(struct pa_threaded_mainloop *mainloop,
			 struct pa_operation *operation)
{
262 263
	assert(mainloop != nullptr);
	assert(operation != nullptr);
264

265 266 267
	pa_operation_state_t state;
	while ((state = pa_operation_get_state(operation))
	       == PA_OPERATION_RUNNING)
268 269 270 271 272 273 274 275 276 277 278 279
		pa_threaded_mainloop_wait(mainloop);

	pa_operation_unref(operation);

	return state == PA_OPERATION_DONE;
}

/**
 * Callback function for stream operation.  It just sends a signal to
 * the caller thread, to wake pulse_wait_for_operation() up.
 */
static void
280 281
pulse_output_stream_success_cb(gcc_unused pa_stream *s,
			       gcc_unused int success, void *userdata)
282
{
283
	PulseOutput &po = *(PulseOutput *)userdata;
284

285
	po.OnStreamSuccess();
286 287
}

288 289
inline void
PulseOutput::OnContextStateChanged(pa_context_state_t new_state)
290
{
291
	switch (new_state) {
292
	case PA_CONTEXT_READY:
293 294
		if (mixer != nullptr)
			pulse_mixer_on_connect(*mixer, context);
295

296
		Signal();
297 298
		break;

299 300
	case PA_CONTEXT_TERMINATED:
	case PA_CONTEXT_FAILED:
301 302
		if (mixer != nullptr)
			pulse_mixer_on_disconnect(*mixer);
303

304 305
		/* the caller thread might be waiting for these
		   states */
306
		Signal();
307 308 309 310 311 312 313 314 315 316
		break;

	case PA_CONTEXT_UNCONNECTED:
	case PA_CONTEXT_CONNECTING:
	case PA_CONTEXT_AUTHORIZING:
	case PA_CONTEXT_SETTING_NAME:
		break;
	}
}

317
static void
318 319 320 321 322 323 324 325 326 327
pulse_output_context_state_cb(struct pa_context *context, void *userdata)
{
	PulseOutput &po = *(PulseOutput *)userdata;

	po.OnContextStateChanged(pa_context_get_state(context));
}

inline void
PulseOutput::OnServerLayoutChanged(pa_subscription_event_type_t t,
				   uint32_t idx)
328
{
329 330 331 332
	pa_subscription_event_type_t facility =
		pa_subscription_event_type_t(t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK);
	pa_subscription_event_type_t type =
		pa_subscription_event_type_t(t & PA_SUBSCRIPTION_EVENT_TYPE_MASK);
333

334
	if (mixer != nullptr &&
335
	    facility == PA_SUBSCRIPTION_EVENT_SINK_INPUT &&
336 337 338
	    stream != nullptr &&
	    pa_stream_get_state(stream) == PA_STREAM_READY &&
	    idx == pa_stream_get_index(stream) &&
339 340
	    (type == PA_SUBSCRIPTION_EVENT_NEW ||
	     type == PA_SUBSCRIPTION_EVENT_CHANGE))
341 342 343 344 345 346 347 348 349 350 351
		pulse_mixer_on_change(*mixer, context, stream);
}

static void
pulse_output_subscribe_cb(gcc_unused pa_context *context,
			  pa_subscription_event_type_t t,
			  uint32_t idx, void *userdata)
{
	PulseOutput &po = *(PulseOutput *)userdata;

	po.OnServerLayoutChanged(t, idx);
352 353
}

354 355
inline void
PulseOutput::Connect()
356
{
357
	assert(context != nullptr);
358

359
	if (pa_context_connect(context, server,
360 361 362
			       (pa_context_flags_t)0, nullptr) < 0)
		throw MakePulseError(context,
				     "pa_context_connect() has failed");
363
}
364

365 366
void
PulseOutput::DeleteStream()
367
{
368
	assert(stream != nullptr);
369

370
	pa_stream_set_suspended_callback(stream, nullptr, nullptr);
371

372 373
	pa_stream_set_state_callback(stream, nullptr, nullptr);
	pa_stream_set_write_callback(stream, nullptr, nullptr);
374

375 376 377
	pa_stream_disconnect(stream);
	pa_stream_unref(stream);
	stream = nullptr;
378 379
}

380 381
void
PulseOutput::DeleteContext()
382
{
383
	assert(context != nullptr);
384

385 386
	pa_context_set_state_callback(context, nullptr, nullptr);
	pa_context_set_subscribe_callback(context, nullptr, nullptr);
387

388 389 390
	pa_context_disconnect(context);
	pa_context_unref(context);
	context = nullptr;
391 392
}

393 394
void
PulseOutput::SetupContext()
395
{
396
	assert(mainloop != nullptr);
397

398 399
	context = pa_context_new(pa_threaded_mainloop_get_api(mainloop),
				 MPD_PULSE_NAME);
400 401
	if (context == nullptr)
		throw std::runtime_error("pa_context_new() has failed");
402

403 404 405 406
	pa_context_set_state_callback(context,
				      pulse_output_context_state_cb, this);
	pa_context_set_subscribe_callback(context,
					  pulse_output_subscribe_cb, this);
407

408 409 410
	try {
		Connect();
	} catch (...) {
411
		DeleteContext();
412
		throw;
413
	}
414 415
}

416
void
417
PulseOutput::Enable()
418
{
419
	assert(mainloop == nullptr);
420

421 422
	/* create the libpulse mainloop and start the thread */

423
	mainloop = pa_threaded_mainloop_new();
424 425
	if (mainloop == nullptr)
		throw std::runtime_error("pa_threaded_mainloop_new() has failed");
426

427
	pa_threaded_mainloop_lock(mainloop);
428

429 430 431 432
	if (pa_threaded_mainloop_start(mainloop) < 0) {
		pa_threaded_mainloop_unlock(mainloop);
		pa_threaded_mainloop_free(mainloop);
		mainloop = nullptr;
433

434
		throw std::runtime_error("pa_threaded_mainloop_start() has failed");
435 436 437 438
	}

	/* create the libpulse context and connect it */

439 440 441
	try {
		SetupContext();
	} catch (...) {
442 443 444 445
		pa_threaded_mainloop_unlock(mainloop);
		pa_threaded_mainloop_stop(mainloop);
		pa_threaded_mainloop_free(mainloop);
		mainloop = nullptr;
446
		throw;
447 448
	}

449
	pa_threaded_mainloop_unlock(mainloop);
450 451
}

452 453
void
PulseOutput::Disable() noexcept
454
{
455
	assert(mainloop != nullptr);
456

457 458 459 460 461
	pa_threaded_mainloop_stop(mainloop);
	if (context != nullptr)
		DeleteContext();
	pa_threaded_mainloop_free(mainloop);
	mainloop = nullptr;
462 463
}

464 465
void
PulseOutput::WaitConnection()
466
{
467
	assert(mainloop != nullptr);
468

469
	pa_context_state_t state;
470

471 472
	if (context == nullptr)
		SetupContext();
473 474

	while (true) {
475
		state = pa_context_get_state(context);
476 477 478
		switch (state) {
		case PA_CONTEXT_READY:
			/* nothing to do */
479
			return;
480 481 482 483 484

		case PA_CONTEXT_UNCONNECTED:
		case PA_CONTEXT_TERMINATED:
		case PA_CONTEXT_FAILED:
			/* failure */
485 486 487 488 489 490
			{
				auto e = MakePulseError(context,
							"failed to connect");
				DeleteContext();
				throw e;
			}
491 492 493 494 495

		case PA_CONTEXT_CONNECTING:
		case PA_CONTEXT_AUTHORIZING:
		case PA_CONTEXT_SETTING_NAME:
			/* wait some more */
496
			pa_threaded_mainloop_wait(mainloop);
497 498
			break;
		}
499
	}
500
}
501

502 503
inline void
PulseOutput::OnStreamSuspended(gcc_unused pa_stream *_stream)
504
{
505 506
	assert(_stream == stream || stream == nullptr);
	assert(mainloop != nullptr);
507 508 509

	/* wake up the main loop to break out of the loop in
	   pulse_output_play() */
510
	Signal();
511 512
}

513
static void
514
pulse_output_stream_suspended_cb(pa_stream *stream, void *userdata)
515
{
516
	PulseOutput &po = *(PulseOutput *)userdata;
517

518 519 520 521 522 523 524 525 526 527
	po.OnStreamSuspended(stream);
}

inline void
PulseOutput::OnStreamStateChanged(pa_stream *_stream,
				  pa_stream_state_t new_state)
{
	assert(_stream == stream || stream == nullptr);
	assert(mainloop != nullptr);
	assert(context != nullptr);
528

529
	switch (new_state) {
530
	case PA_STREAM_READY:
531 532
		if (mixer != nullptr)
			pulse_mixer_on_change(*mixer, context, _stream);
533

534
		Signal();
535 536
		break;

537 538
	case PA_STREAM_FAILED:
	case PA_STREAM_TERMINATED:
539 540
		if (mixer != nullptr)
			pulse_mixer_on_disconnect(*mixer);
541

542
		Signal();
543 544 545 546 547 548 549
		break;

	case PA_STREAM_UNCONNECTED:
	case PA_STREAM_CREATING:
		break;
	}
}
550

551 552 553 554 555 556 557 558 559 560 561 562 563 564
static void
pulse_output_stream_state_cb(pa_stream *stream, void *userdata)
{
	PulseOutput &po = *(PulseOutput *)userdata;

	return po.OnStreamStateChanged(stream, pa_stream_get_state(stream));
}

inline void
PulseOutput::OnStreamWrite(size_t nbytes)
{
	assert(mainloop != nullptr);

	writable = nbytes;
565
	Signal();
566 567
}

568
static void
569
pulse_output_stream_write_cb(gcc_unused pa_stream *stream, size_t nbytes,
570 571
			     void *userdata)
{
572
	PulseOutput &po = *(PulseOutput *)userdata;
573

574
	return po.OnStreamWrite(nbytes);
575 576
}

577 578
inline void
PulseOutput::SetupStream(const pa_sample_spec &ss)
579
{
580
	assert(context != nullptr);
581

582 583
	/* WAVE-EX is been adopted as the speaker map for most media files */
	pa_channel_map chan_map;
584 585
	pa_channel_map_init_extend(&chan_map, ss.channels,
				   PA_CHANNEL_MAP_WAVEEX);
586
	stream = pa_stream_new(context, name, &ss, &chan_map);
587 588 589
	if (stream == nullptr)
		throw MakePulseError(context,
				     "pa_stream_new() has failed");
590

591 592 593
	pa_stream_set_suspended_callback(stream,
					 pulse_output_stream_suspended_cb,
					 this);
594

595 596 597 598
	pa_stream_set_state_callback(stream,
				     pulse_output_stream_state_cb, this);
	pa_stream_set_write_callback(stream,
				     pulse_output_stream_write_cb, this);
599 600
}

601
void
602
PulseOutput::Open(AudioFormat &audio_format)
603
{
604
	assert(mainloop != nullptr);
605

606
	Pulse::LockGuard lock(mainloop);
607

608 609
	if (context != nullptr) {
		switch (pa_context_get_state(context)) {
610 611 612 613 614 615
		case PA_CONTEXT_UNCONNECTED:
		case PA_CONTEXT_TERMINATED:
		case PA_CONTEXT_FAILED:
			/* the connection was closed meanwhile; delete
			   it, and pulse_output_wait_connection() will
			   reopen it */
616
			DeleteContext();
617 618 619 620 621 622 623 624 625 626
			break;

		case PA_CONTEXT_READY:
		case PA_CONTEXT_CONNECTING:
		case PA_CONTEXT_AUTHORIZING:
		case PA_CONTEXT_SETTING_NAME:
			break;
		}
	}

627
	WaitConnection();
628

629 630
	/* Use the sample formats that our version of PulseAudio and MPD
	   have in common, otherwise force MPD to send 16 bit */
631

632
	pa_sample_spec ss;
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652

	switch (audio_format.format) {
	case SampleFormat::FLOAT:
		ss.format = PA_SAMPLE_FLOAT32NE;
		break;
	case SampleFormat::S32:
		ss.format = PA_SAMPLE_S32NE;
		break;
	case SampleFormat::S24_P32:
		ss.format = PA_SAMPLE_S24_32NE;
		break;
	case SampleFormat::S16:
		ss.format = PA_SAMPLE_S16NE;
		break;
	default:
		audio_format.format = SampleFormat::S16;
		ss.format = PA_SAMPLE_S16NE;
		break;
	}

653 654
	ss.rate = audio_format.sample_rate;
	ss.channels = audio_format.channels;
655

656 657
	/* create a stream .. */

658
	SetupStream(ss);
659 660 661

	/* .. and connect it (asynchronously) */

662
	if (pa_stream_connect_playback(stream, sink,
663 664
				       nullptr, pa_stream_flags_t(0),
				       nullptr, nullptr) < 0) {
665
		DeleteStream();
666

667 668
		throw MakePulseError(context,
				     "pa_stream_connect_playback() has failed");
669
	}
670 671

	pause = false;
672 673
}

674 675
void
PulseOutput::Close() noexcept
676
{
677
	assert(mainloop != nullptr);
678

679
	Pulse::LockGuard lock(mainloop);
680

681 682 683 684
	if (pa_stream_get_state(stream) == PA_STREAM_READY) {
		pa_operation *o =
			pa_stream_drain(stream,
					pulse_output_stream_success_cb, this);
685
		if (o == nullptr) {
686
			LogPulseError(context,
687
				      "pa_stream_drain() has failed");
688
		} else
689
			pulse_wait_for_operation(mainloop, o);
690 691
	}

692
	DeleteStream();
693

694 695 696
	if (context != nullptr &&
	    pa_context_get_state(context) != PA_CONTEXT_READY)
		DeleteContext();
697 698
}

699 700
void
PulseOutput::WaitStream()
701
{
702
	while (true) {
703
		switch (pa_stream_get_state(stream)) {
704
		case PA_STREAM_READY:
705
			return;
706

707 708 709
		case PA_STREAM_FAILED:
		case PA_STREAM_TERMINATED:
		case PA_STREAM_UNCONNECTED:
710 711
			throw MakePulseError(context,
					     "failed to connect the stream");
712

713
		case PA_STREAM_CREATING:
714
			pa_threaded_mainloop_wait(mainloop);
715 716
			break;
		}
717
	}
718 719
}

720
void
721
PulseOutput::StreamPause(bool _pause)
722
{
723 724 725
	assert(mainloop != nullptr);
	assert(context != nullptr);
	assert(stream != nullptr);
726

727
	pa_operation *o = pa_stream_cork(stream, _pause,
728
					 pulse_output_stream_success_cb, this);
729 730 731
	if (o == nullptr)
		throw MakePulseError(context,
				     "pa_stream_cork() has failed");
732

733 734 735
	if (!pulse_wait_for_operation(mainloop, o))
		throw MakePulseError(context,
				     "pa_stream_cork() has failed");
736 737
}

738 739
std::chrono::steady_clock::duration
PulseOutput::Delay() const noexcept
740
{
741
	Pulse::LockGuard lock(mainloop);
742

743
	auto result = std::chrono::steady_clock::duration::zero();
744
	if (pause && pa_stream_is_corked(stream) &&
745
	    pa_stream_get_state(stream) == PA_STREAM_READY)
746
		/* idle while paused */
747
		result = std::chrono::seconds(1);
748 749 750 751

	return result;
}

752
size_t
753
PulseOutput::Play(const void *chunk, size_t size)
754
{
755 756
	assert(mainloop != nullptr);
	assert(stream != nullptr);
757

758
	Pulse::LockGuard lock(mainloop);
759

760 761
	pause = false;

762 763
	/* check if the stream is (already) connected */

764
	WaitStream();
765

766
	assert(context != nullptr);
767 768 769

	/* unpause if previously paused */

770 771
	if (pa_stream_is_corked(stream))
		StreamPause(false);
772 773 774

	/* wait until the server allows us to write */

775
	while (writable == 0) {
776 777
		if (pa_stream_is_suspended(stream))
			throw std::runtime_error("suspended");
778

779
		pa_threaded_mainloop_wait(mainloop);
780

781 782
		if (pa_stream_get_state(stream) != PA_STREAM_READY)
			throw std::runtime_error("disconnected");
783 784 785 786
	}

	/* now write */

787
	if (size > writable)
788
		/* don't send more than possible */
789
		size = writable;
790

791
	writable -= size;
792

793
	int result = pa_stream_write(stream, chunk, size, nullptr,
794
				     0, PA_SEEK_RELATIVE);
795 796
	if (result < 0)
		throw MakePulseError(context, "pa_stream_write() failed");
797

798
	return size;
799 800
}

801 802
void
PulseOutput::Cancel() noexcept
803
{
804 805
	assert(mainloop != nullptr);
	assert(stream != nullptr);
806

807
	Pulse::LockGuard lock(mainloop);
808

809
	if (pa_stream_get_state(stream) != PA_STREAM_READY) {
810 811 812 813 814
		/* no need to flush when the stream isn't connected
		   yet */
		return;
	}

815
	assert(context != nullptr);
816

817 818 819
	pa_operation *o = pa_stream_flush(stream,
					  pulse_output_stream_success_cb,
					  this);
820
	if (o == nullptr) {
821
		LogPulseError(context, "pa_stream_flush() has failed");
822 823 824
		return;
	}

825
	pulse_wait_for_operation(mainloop, o);
826 827
}

828
bool
829
PulseOutput::Pause()
830
{
831 832
	assert(mainloop != nullptr);
	assert(stream != nullptr);
833

834
	Pulse::LockGuard lock(mainloop);
835

836 837
	pause = true;

838 839
	/* check if the stream is (already/still) connected */

840
	WaitStream();
841

842
	assert(context != nullptr);
843 844 845

	/* cork the stream */

846 847
	if (!pa_stream_is_corked(stream))
		StreamPause(true);
848 849 850 851

	return true;
}

852 853
inline bool
PulseOutput::TestDefaultDevice()
854
try {
855
	const ConfigBlock empty;
856
	PulseOutput po(empty);
857 858
	po.Enable();
	AtScopeExit(&po) { po.Disable(); };
859
	po.WaitConnection();
860

861
	return true;
862
} catch (...) {
863
	return false;
864 865
}

866 867 868 869 870 871
static bool
pulse_output_test_default_device(void)
{
	return PulseOutput::TestDefaultDevice();
}

872
const struct AudioOutputPlugin pulse_output_plugin = {
873 874
	"pulse",
	pulse_output_test_default_device,
875
	PulseOutput::Create,
876
	&pulse_mixer_plugin,
877
};