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 #include "Control.hxx"
21 #include "MusicPipe.hxx"
22 #include "song/DetachedSong.hxx"
23 
24 #include <cassert>
25 #include <stdexcept>
26 
DecoderControl(Mutex & _mutex,Cond & _client_cond,InputCacheManager * _input_cache,const AudioFormat _configured_audio_format,const ReplayGainConfig & _replay_gain_config)27 DecoderControl::DecoderControl(Mutex &_mutex, Cond &_client_cond,
28 			       InputCacheManager *_input_cache,
29 			       const AudioFormat _configured_audio_format,
30 			       const ReplayGainConfig &_replay_gain_config) noexcept
31 	:thread(BIND_THIS_METHOD(RunThread)),
32 	 input_cache(_input_cache),
33 	 mutex(_mutex), client_cond(_client_cond),
34 	 configured_audio_format(_configured_audio_format),
35 	 replay_gain_config(_replay_gain_config) {}
36 
~DecoderControl()37 DecoderControl::~DecoderControl() noexcept
38 {
39 	ClearError();
40 }
41 
42 void
SetReady(const AudioFormat audio_format,bool _seekable,SignedSongTime _duration)43 DecoderControl::SetReady(const AudioFormat audio_format,
44 			 bool _seekable, SignedSongTime _duration) noexcept
45 {
46 	assert(state == DecoderState::START);
47 	assert(pipe != nullptr);
48 	assert(pipe->IsEmpty());
49 	assert(audio_format.IsDefined());
50 	assert(audio_format.IsValid());
51 
52 	in_audio_format = audio_format;
53 	out_audio_format = audio_format.WithMask(configured_audio_format);
54 
55 	seekable = _seekable;
56 	total_time = _duration;
57 
58 	state = DecoderState::DECODE;
59 	client_cond.notify_one();
60 }
61 
62 bool
IsCurrentSong(const DetachedSong & _song) const63 DecoderControl::IsCurrentSong(const DetachedSong &_song) const noexcept
64 {
65 	switch (state) {
66 	case DecoderState::STOP:
67 	case DecoderState::ERROR:
68 		return false;
69 
70 	case DecoderState::START:
71 	case DecoderState::DECODE:
72 		return song->IsSame(_song);
73 	}
74 
75 	assert(false);
76 	gcc_unreachable();
77 }
78 
79 void
Start(std::unique_lock<Mutex> & lock,std::unique_ptr<DetachedSong> _song,SongTime _start_time,SongTime _end_time,bool _initial_seek_essential,MusicBuffer & _buffer,std::shared_ptr<MusicPipe> _pipe)80 DecoderControl::Start(std::unique_lock<Mutex> &lock,
81 		      std::unique_ptr<DetachedSong> _song,
82 		      SongTime _start_time, SongTime _end_time,
83 		      bool _initial_seek_essential,
84 		      MusicBuffer &_buffer,
85 		      std::shared_ptr<MusicPipe> _pipe) noexcept
86 {
87 	assert(_song != nullptr);
88 	assert(_pipe->IsEmpty());
89 
90 	song = std::move(_song);
91 	start_time = _start_time;
92 	end_time = _end_time;
93 	initial_seek_essential = _initial_seek_essential;
94 	buffer = &_buffer;
95 	pipe = std::move(_pipe);
96 
97 	ClearError();
98 	SynchronousCommandLocked(lock, DecoderCommand::START);
99 }
100 
101 void
Stop(std::unique_lock<Mutex> & lock)102 DecoderControl::Stop(std::unique_lock<Mutex> &lock) noexcept
103 {
104 	if (command != DecoderCommand::NONE)
105 		/* Attempt to cancel the current command.  If it's too
106 		   late and the decoder thread is already executing
107 		   the old command, we'll call STOP again in this
108 		   function (see below). */
109 		SynchronousCommandLocked(lock, DecoderCommand::STOP);
110 
111 	if (state != DecoderState::STOP && state != DecoderState::ERROR)
112 		SynchronousCommandLocked(lock, DecoderCommand::STOP);
113 }
114 
115 void
Seek(std::unique_lock<Mutex> & lock,SongTime t)116 DecoderControl::Seek(std::unique_lock<Mutex> &lock, SongTime t)
117 {
118 	assert(state != DecoderState::START);
119 	assert(state != DecoderState::ERROR);
120 
121 	switch (state) {
122 	case DecoderState::START:
123 	case DecoderState::ERROR:
124 		gcc_unreachable();
125 
126 	case DecoderState::STOP:
127 		/* TODO: if this happens, the caller should be given a
128 		   chance to restart the decoder */
129 		throw std::runtime_error("Decoder is dead");
130 
131 	case DecoderState::DECODE:
132 		break;
133 	}
134 
135 	if (!seekable)
136 		throw std::runtime_error("Not seekable");
137 
138 	seek_time = t;
139 	seek_error = false;
140 	SynchronousCommandLocked(lock, DecoderCommand::SEEK);
141 
142 	while (state == DecoderState::START)
143 		/* If the decoder falls back to DecoderState::START,
144 		   this means that our SEEK command arrived too late,
145 		   and the decoder had meanwhile finished decoding and
146 		   went idle.  Our SEEK command is finished, but that
147 		   means only that the decoder thread has launched the
148 		   decoder.  To work around illegal states, we wait
149 		   until the decoder plugin has become ready.  This is
150 		   a kludge, built on top of the "late seek" kludge.
151 		   Not exactly elegant, sorry. */
152 		WaitForDecoder(lock);
153 
154 	if (seek_error)
155 		throw std::runtime_error("Decoder failed to seek");
156 }
157 
158 void
Quit()159 DecoderControl::Quit() noexcept
160 {
161 	assert(thread.IsDefined());
162 
163 	quit = true;
164 	LockAsynchronousCommand(DecoderCommand::STOP);
165 
166 	thread.Join();
167 }
168 
169 void
CycleMixRamp()170 DecoderControl::CycleMixRamp() noexcept
171 {
172 	previous_mix_ramp = std::move(mix_ramp);
173 	mix_ramp = {};
174 }
175