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