1 /*
2  * Copyright 2003-2021 The Music Player Daemon Project
3  * http://www.musicpd.org
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #ifndef MPD_PLAYER_CONTROL_HXX
21 #define MPD_PLAYER_CONTROL_HXX
22 
23 #include "output/Client.hxx"
24 #include "pcm/AudioFormat.hxx"
25 #include "thread/Mutex.hxx"
26 #include "thread/Cond.hxx"
27 #include "thread/Thread.hxx"
28 #include "CrossFade.hxx"
29 #include "Chrono.hxx"
30 #include "ReplayGainConfig.hxx"
31 #include "ReplayGainMode.hxx"
32 #include "MusicChunkPtr.hxx"
33 
34 #include <cstdint>
35 #include <exception>
36 #include <memory>
37 
38 struct Tag;
39 class PlayerListener;
40 class PlayerOutputs;
41 class InputCacheManager;
42 class DetachedSong;
43 
44 enum class PlayerState : uint8_t {
45 	STOP,
46 	PAUSE,
47 	PLAY
48 };
49 
50 enum class PlayerCommand : uint8_t {
51 	NONE,
52 	EXIT,
53 	STOP,
54 	PAUSE,
55 
56 	/**
57 	 * Seek to a certain position in the specified song.  This
58 	 * command can also be used to change the current song or
59 	 * start playback.  It "finishes" immediately, but
60 	 * PlayerControl::seeking will be set until seeking really
61 	 * completes (or fails).
62 	 */
63 	SEEK,
64 
65 	CLOSE_AUDIO,
66 
67 	/**
68 	 * At least one AudioOutput.enabled flag has been modified;
69 	 * commit those changes to the output threads.
70 	 */
71 	UPDATE_AUDIO,
72 
73 	/** PlayerControl.next_song has been updated */
74 	QUEUE,
75 
76 	/**
77 	 * cancel pre-decoding PlayerControl.next_song; if the player
78 	 * has already started playing this song, it will completely
79 	 * stop
80 	 */
81 	CANCEL,
82 
83 	/**
84 	 * Refresh status information in the #PlayerControl struct,
85 	 * e.g. elapsed_time.
86 	 */
87 	REFRESH,
88 };
89 
90 enum class PlayerError : uint8_t {
91 	NONE,
92 
93 	/**
94 	 * The decoder has failed to decode the song.
95 	 */
96 	DECODER,
97 
98 	/**
99 	 * The audio output has failed.
100 	 */
101 	OUTPUT,
102 };
103 
104 struct PlayerStatus {
105 	PlayerState state;
106 	uint16_t bit_rate;
107 	AudioFormat audio_format;
108 	SignedSongTime total_time;
109 	SongTime elapsed_time;
110 };
111 
112 class PlayerControl final : public AudioOutputClient {
113 	friend class Player;
114 
115 	PlayerListener &listener;
116 
117 	PlayerOutputs &outputs;
118 
119 	InputCacheManager *const input_cache;
120 
121 	const unsigned buffer_chunks;
122 
123 	/**
124 	 * The "audio_output_format" setting.
125 	 */
126 	const AudioFormat configured_audio_format;
127 
128 	/**
129 	 * The handle of the player thread.
130 	 */
131 	Thread thread;
132 
133 	/**
134 	 * This lock protects #command, #state, #error, #tagged_song.
135 	 */
136 	mutable Mutex mutex;
137 
138 	/**
139 	 * Trigger this object after you have modified #command.
140 	 */
141 	Cond cond;
142 
143 	/**
144 	 * This object gets signalled when the player thread has
145 	 * finished the #command.  It wakes up the client that waits
146 	 * (i.e. the main thread).
147 	 */
148 	Cond client_cond;
149 
150 	/**
151 	 * The error that occurred in the player thread.  This
152 	 * attribute is only valid if #error_type is not
153 	 * #PlayerError::NONE.  The object must be freed when this
154 	 * object transitions back to #PlayerError::NONE.
155 	 */
156 	std::exception_ptr error;
157 
158 	/**
159 	 * The next queued song.
160 	 *
161 	 * This is a duplicate, and must be freed when this attribute
162 	 * is cleared.
163 	 */
164 	std::unique_ptr<DetachedSong> next_song;
165 
166 	/**
167 	 * A copy of the current #DetachedSong after its tags have
168 	 * been updated by the decoder (for example, a radio stream
169 	 * that has sent a new tag after switching to the next song).
170 	 * This shall be used by PlayerListener::OnPlayerTagModified()
171 	 * to update the current #DetachedSong in the queue.
172 	 *
173 	 * Protected by #mutex.  Set by the PlayerThread and consumed
174 	 * by the main thread.
175 	 */
176 	std::unique_ptr<DetachedSong> tagged_song;
177 
178 	PlayerCommand command = PlayerCommand::NONE;
179 	PlayerState state = PlayerState::STOP;
180 
181 	PlayerError error_type = PlayerError::NONE;
182 
183 	ReplayGainMode replay_gain_mode = ReplayGainMode::OFF;
184 
185 	/**
186 	 * Is the player currently busy with the SEEK command?
187 	 */
188 	bool seeking = false;
189 
190 	/**
191 	 * If this flag is set, then the player will be auto-paused at
192 	 * the end of the song, before the next song starts to play.
193 	 *
194 	 * This is a copy of the queue's "single" flag most of the
195 	 * time.
196 	 */
197 	bool border_pause = false;
198 
199 	/**
200 	 * If this flag is set, then the player thread is currently
201 	 * occupied and will not be able to respond quickly to
202 	 * commands (e.g. waiting for the decoder thread to finish
203 	 * seeking).  This is used to skip #PlayerCommand::REFRESH to
204 	 * avoid blocking the main thread.
205 	 */
206 	bool occupied = false;
207 
208 	struct ScopeOccupied {
209 		PlayerControl &pc;
210 
ScopeOccupiedPlayerControl::ScopeOccupied211 		explicit ScopeOccupied(PlayerControl &_pc) noexcept:pc(_pc) {
212 			assert(!pc.occupied);
213 			pc.occupied = true;
214 		}
215 
~ScopeOccupiedPlayerControl::ScopeOccupied216 		~ScopeOccupied() noexcept {
217 			assert(pc.occupied);
218 			pc.occupied = false;
219 		}
220 	};
221 
222 	AudioFormat audio_format;
223 	uint16_t bit_rate;
224 
225 	SignedSongTime total_time;
226 	SongTime elapsed_time;
227 
228 	SongTime seek_time;
229 
230 	CrossFadeSettings cross_fade;
231 
232 	const ReplayGainConfig replay_gain_config;
233 
234 	FloatDuration total_play_time = FloatDuration::zero();
235 
236 public:
237 	PlayerControl(PlayerListener &_listener,
238 		      PlayerOutputs &_outputs,
239 		      InputCacheManager *_input_cache,
240 		      unsigned buffer_chunks,
241 		      AudioFormat _configured_audio_format,
242 		      const ReplayGainConfig &_replay_gain_config) noexcept;
243 	~PlayerControl() noexcept;
244 
245 	void Kill() noexcept;
246 
247 	/**
248 	 * Like CheckRethrowError(), but locks and unlocks the object.
249 	 */
LockCheckRethrowError() const250 	void LockCheckRethrowError() const {
251 		const std::scoped_lock<Mutex> protect(mutex);
252 		CheckRethrowError();
253 	}
254 
255 	void LockClearError() noexcept;
256 
GetErrorType() const257 	PlayerError GetErrorType() const noexcept {
258 		return error_type;
259 	}
260 
261 	void LockUpdateAudio() noexcept;
262 
263 	/**
264 	 * Throws on error.
265 	 *
266 	 * @param song the song to be queued
267 	 */
268 	void Play(std::unique_ptr<DetachedSong> song);
269 
270 	/**
271 	 * @param song the song to be queued; the given instance will be owned
272 	 * and freed by the player
273 	 */
274 	void LockEnqueueSong(std::unique_ptr<DetachedSong> song) noexcept;
275 
276 	/**
277 	 * Makes the player thread seek the specified song to a position.
278 	 *
279 	 * Throws on error.
280 	 *
281 	 * @param song the song to be queued; the given instance will be owned
282 	 * and freed by the player
283 	 */
284 	void LockSeek(std::unique_ptr<DetachedSong> song, SongTime t);
285 
286 	void LockStop() noexcept;
287 
288 	/**
289 	 * see PlayerCommand::CANCEL
290 	 */
291 	void LockCancel() noexcept;
292 
293 	void LockSetPause(bool pause_flag) noexcept;
294 
295 	void LockPause() noexcept;
296 
297 	/**
298 	 * Set the player's #border_pause flag.
299 	 */
300 	void LockSetBorderPause(bool border_pause) noexcept;
301 	void SetCrossFade(FloatDuration duration) noexcept;
302 
GetCrossFade() const303 	auto GetCrossFade() const noexcept {
304 		return cross_fade.duration;
305 	}
306 
307 	void SetMixRampDb(float mixramp_db) noexcept;
308 
GetMixRampDb() const309 	float GetMixRampDb() const noexcept {
310 		return cross_fade.mixramp_db;
311 	}
312 
313 	void SetMixRampDelay(FloatDuration mixramp_delay) noexcept;
314 
GetMixRampDelay() const315 	auto GetMixRampDelay() const noexcept {
316 		return cross_fade.mixramp_delay;
317 	}
318 
LockSetReplayGainMode(ReplayGainMode _mode)319 	void LockSetReplayGainMode(ReplayGainMode _mode) noexcept {
320 		const std::scoped_lock<Mutex> protect(mutex);
321 		replay_gain_mode = _mode;
322 	}
323 
324 	/**
325 	 * Like ReadTaggedSong(), but locks and unlocks the object.
326 	 */
327 	std::unique_ptr<DetachedSong> LockReadTaggedSong() noexcept;
328 
329 	[[gnu::pure]]
330 	PlayerStatus LockGetStatus() noexcept;
331 
GetState() const332 	PlayerState GetState() const noexcept {
333 		return state;
334 	}
335 
336 	struct SyncInfo {
337 		PlayerState state;
338 		bool has_next_song;
339 	};
340 
341 	[[gnu::pure]]
LockGetSyncInfo() const342 	SyncInfo LockGetSyncInfo() const noexcept {
343 		const std::scoped_lock<Mutex> protect(mutex);
344 		return {state, next_song != nullptr};
345 	}
346 
GetTotalPlayTime() const347 	auto GetTotalPlayTime() const noexcept {
348 		return total_play_time;
349 	}
350 
351 private:
352 	/**
353 	 * Signals the object.  The object should be locked prior to
354 	 * calling this function.
355 	 */
Signal()356 	void Signal() noexcept {
357 		cond.notify_one();
358 	}
359 
360 	/**
361 	 * Signals the object.  The object is temporarily locked by
362 	 * this function.
363 	 */
LockSignal()364 	void LockSignal() noexcept {
365 		const std::scoped_lock<Mutex> protect(mutex);
366 		Signal();
367 	}
368 
369 	/**
370 	 * Waits for a signal on the object.  This function is only
371 	 * valid in the player thread.  The object must be locked
372 	 * prior to calling this function.
373 	 */
Wait(std::unique_lock<Mutex> & lock)374 	void Wait(std::unique_lock<Mutex> &lock) noexcept {
375 		assert(thread.IsInside());
376 
377 		cond.wait(lock);
378 	}
379 
380 	/**
381 	 * Wake up the client waiting for command completion.
382 	 *
383 	 * Caller must lock the object.
384 	 */
ClientSignal()385 	void ClientSignal() noexcept {
386 		assert(thread.IsInside());
387 
388 		client_cond.notify_one();
389 	}
390 
391 	/**
392 	 * The client calls this method to wait for command
393 	 * completion.
394 	 *
395 	 * Caller must lock the object.
396 	 */
ClientWait(std::unique_lock<Mutex> & lock)397 	void ClientWait(std::unique_lock<Mutex> &lock) noexcept {
398 		assert(!thread.IsInside());
399 
400 		client_cond.wait(lock);
401 	}
402 
403 	/**
404 	 * A command has been finished.  This method clears the
405 	 * command and signals the client.
406 	 *
407 	 * To be called from the player thread.  Caller must lock the
408 	 * object.
409 	 */
CommandFinished()410 	void CommandFinished() noexcept {
411 		assert(command != PlayerCommand::NONE);
412 
413 		command = PlayerCommand::NONE;
414 		ClientSignal();
415 	}
416 
LockCommandFinished()417 	void LockCommandFinished() noexcept {
418 		const std::scoped_lock<Mutex> protect(mutex);
419 		CommandFinished();
420 	}
421 
422 	/**
423 	 * Checks if the size of the #MusicPipe is below the #threshold.  If
424 	 * not, it attempts to synchronize with all output threads, and waits
425 	 * until another #MusicChunk is finished.
426 	 *
427 	 * Caller must lock the mutex.
428 	 *
429 	 * @param threshold the maximum number of chunks in the pipe
430 	 * @return true if there are less than #threshold chunks in the pipe
431 	 */
432 	bool WaitOutputConsumed(std::unique_lock<Mutex> &lock,
433 				unsigned threshold) noexcept;
434 
LockWaitOutputConsumed(unsigned threshold)435 	bool LockWaitOutputConsumed(unsigned threshold) noexcept {
436 		std::unique_lock<Mutex> lock(mutex);
437 		return WaitOutputConsumed(lock, threshold);
438 	}
439 
440 	/**
441 	 * Wait for the command to be finished by the player thread.
442 	 *
443 	 * To be called from the main thread.  Caller must lock the
444 	 * object.
445 	 */
WaitCommandLocked(std::unique_lock<Mutex> & lock)446 	void WaitCommandLocked(std::unique_lock<Mutex> &lock) noexcept {
447 		while (command != PlayerCommand::NONE)
448 			ClientWait(lock);
449 	}
450 
451 	/**
452 	 * Send a command to the player thread and synchronously wait
453 	 * for it to finish.
454 	 *
455 	 * To be called from the main thread.  Caller must lock the
456 	 * object.
457 	 */
SynchronousCommand(std::unique_lock<Mutex> & lock,PlayerCommand cmd)458 	void SynchronousCommand(std::unique_lock<Mutex> &lock,
459 				PlayerCommand cmd) noexcept {
460 		assert(command == PlayerCommand::NONE);
461 
462 		command = cmd;
463 		Signal();
464 		WaitCommandLocked(lock);
465 	}
466 
467 	/**
468 	 * Send a command to the player thread and synchronously wait
469 	 * for it to finish.
470 	 *
471 	 * To be called from the main thread.  This method locks the
472 	 * object.
473 	 */
LockSynchronousCommand(PlayerCommand cmd)474 	void LockSynchronousCommand(PlayerCommand cmd) noexcept {
475 		std::unique_lock<Mutex> lock(mutex);
476 		SynchronousCommand(lock, cmd);
477 	}
478 
479 	void PauseLocked(std::unique_lock<Mutex> &lock) noexcept;
480 
ClearError()481 	void ClearError() noexcept {
482 		error_type = PlayerError::NONE;
483 		error = std::exception_ptr();
484 	}
485 
ApplyBorderPause()486 	bool ApplyBorderPause() noexcept {
487 		if (border_pause)
488 			state = PlayerState::PAUSE;
489 		return border_pause;
490 	}
491 
492 	/**
493 	 * Set the error.  Discards any previous error condition.
494 	 *
495 	 * Caller must lock the object.
496 	 *
497 	 * @param type the error type; must not be #PlayerError::NONE
498 	 */
499 	void SetError(PlayerError type, std::exception_ptr &&_error) noexcept;
500 
501 	/**
502 	 * Set the error and set state to PlayerState::PAUSE.
503 	 */
SetOutputError(std::exception_ptr && _error)504 	void SetOutputError(std::exception_ptr &&_error) noexcept {
505 		SetError(PlayerError::OUTPUT, std::move(_error));
506 
507 		/* pause: the user may resume playback as soon as an
508 		   audio output becomes available */
509 		state = PlayerState::PAUSE;
510 	}
511 
LockSetOutputError(std::exception_ptr && _error)512 	void LockSetOutputError(std::exception_ptr &&_error) noexcept {
513 		const std::scoped_lock<Mutex> lock(mutex);
514 		SetOutputError(std::move(_error));
515 	}
516 
517 	/**
518 	 * Checks whether an error has occurred, and if so, rethrows
519 	 * it.
520 	 *
521 	 * Caller must lock the object.
522 	 */
CheckRethrowError() const523 	void CheckRethrowError() const {
524 		if (error_type != PlayerError::NONE)
525 			std::rethrow_exception(error);
526 	}
527 
528 	/**
529 	 * Set the #tagged_song attribute to a newly allocated copy of
530 	 * the given #DetachedSong.  Locks and unlocks the object.
531 	 */
532 	void LockSetTaggedSong(const DetachedSong &song) noexcept;
533 
534 	void ClearTaggedSong() noexcept;
535 
536 	/**
537 	 * Read and clear the #tagged_song attribute.
538 	 *
539 	 * Caller must lock the object.
540 	 */
541 	std::unique_ptr<DetachedSong> ReadTaggedSong() noexcept;
542 
543 	void EnqueueSongLocked(std::unique_lock<Mutex> &lock,
544 			       std::unique_ptr<DetachedSong> song) noexcept;
545 
546 	/**
547 	 * Throws on error.
548 	 */
549 	void SeekLocked(std::unique_lock<Mutex> &lock,
550 			std::unique_ptr<DetachedSong> song, SongTime t);
551 
552 	/**
553 	 * Caller must lock the object.
554 	 */
CancelPendingSeek()555 	void CancelPendingSeek() noexcept {
556 		if (!seeking)
557 			return;
558 
559 		seeking = false;
560 		ClientSignal();
561 	}
562 
563 	void LockUpdateSongTag(DetachedSong &song,
564 			       const Tag &new_tag) noexcept;
565 
566 	/**
567 	 * Plays a #MusicChunk object (after applying software
568 	 * volume).  If it contains a (stream) tag, copy it to the
569 	 * current song, so MPD's playlist reflects the new stream
570 	 * tag.
571 	 *
572 	 * Player lock is not held.
573 	 *
574 	 * Throws on error.
575 	 */
576 	void PlayChunk(DetachedSong &song, MusicChunkPtr chunk,
577 		       const AudioFormat &format);
578 
579 	/* virtual methods from AudioOutputClient */
ChunksConsumed()580 	void ChunksConsumed() override {
581 		LockSignal();
582 	}
583 
ApplyEnabled()584 	void ApplyEnabled() override {
585 		LockUpdateAudio();
586 	}
587 
588 	void RunThread() noexcept;
589 };
590 
591 #endif
592