summaryrefslogtreecommitdiff
path: root/src/decoder/Control.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/decoder/Control.cxx')
-rw-r--r--src/decoder/Control.cxx171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/decoder/Control.cxx b/src/decoder/Control.cxx
new file mode 100644
index 000000000..5cf0d1d7f
--- /dev/null
+++ b/src/decoder/Control.cxx
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2003-2017 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include "Control.hxx"
+#include "MusicPipe.hxx"
+#include "song/DetachedSong.hxx"
+
+#include <stdexcept>
+
+#include <assert.h>
+
+DecoderControl::DecoderControl(Mutex &_mutex, Cond &_client_cond,
+ const AudioFormat _configured_audio_format,
+ const ReplayGainConfig &_replay_gain_config) noexcept
+ :thread(BIND_THIS_METHOD(RunThread)),
+ mutex(_mutex), client_cond(_client_cond),
+ configured_audio_format(_configured_audio_format),
+ replay_gain_config(_replay_gain_config) {}
+
+DecoderControl::~DecoderControl() noexcept
+{
+ ClearError();
+}
+
+void
+DecoderControl::WaitForDecoder() noexcept
+{
+ assert(!client_is_waiting);
+ client_is_waiting = true;
+
+ client_cond.wait(mutex);
+
+ assert(client_is_waiting);
+ client_is_waiting = false;
+}
+
+void
+DecoderControl::SetReady(const AudioFormat audio_format,
+ bool _seekable, SignedSongTime _duration) noexcept
+{
+ assert(state == DecoderState::START);
+ assert(pipe != nullptr);
+ assert(pipe->IsEmpty());
+ assert(audio_format.IsDefined());
+ assert(audio_format.IsValid());
+
+ in_audio_format = audio_format;
+ out_audio_format = audio_format.WithMask(configured_audio_format);
+
+ seekable = _seekable;
+ total_time = _duration;
+
+ state = DecoderState::DECODE;
+ client_cond.signal();
+}
+
+bool
+DecoderControl::IsCurrentSong(const DetachedSong &_song) const noexcept
+{
+ switch (state) {
+ case DecoderState::STOP:
+ case DecoderState::ERROR:
+ return false;
+
+ case DecoderState::START:
+ case DecoderState::DECODE:
+ return song->IsSame(_song);
+ }
+
+ assert(false);
+ gcc_unreachable();
+}
+
+void
+DecoderControl::Start(std::unique_ptr<DetachedSong> _song,
+ SongTime _start_time, SongTime _end_time,
+ MusicBuffer &_buffer,
+ std::shared_ptr<MusicPipe> _pipe) noexcept
+{
+ assert(_song != nullptr);
+ assert(_pipe->IsEmpty());
+
+ song = std::move(_song);
+ start_time = _start_time;
+ end_time = _end_time;
+ buffer = &_buffer;
+ pipe = std::move(_pipe);
+
+ ClearError();
+ SynchronousCommandLocked(DecoderCommand::START);
+}
+
+void
+DecoderControl::Stop() noexcept
+{
+ if (command != DecoderCommand::NONE)
+ /* Attempt to cancel the current command. If it's too
+ late and the decoder thread is already executing
+ the old command, we'll call STOP again in this
+ function (see below). */
+ SynchronousCommandLocked(DecoderCommand::STOP);
+
+ if (state != DecoderState::STOP && state != DecoderState::ERROR)
+ SynchronousCommandLocked(DecoderCommand::STOP);
+}
+
+void
+DecoderControl::Seek(SongTime t)
+{
+ assert(state != DecoderState::START);
+ assert(state != DecoderState::ERROR);
+
+ switch (state) {
+ case DecoderState::START:
+ case DecoderState::ERROR:
+ gcc_unreachable();
+
+ case DecoderState::STOP:
+ /* TODO: if this happens, the caller should be given a
+ chance to restart the decoder */
+ throw std::runtime_error("Decoder is dead");
+
+ case DecoderState::DECODE:
+ break;
+ }
+
+ if (!seekable)
+ throw std::runtime_error("Not seekable");
+
+ seek_time = t;
+ seek_error = false;
+ SynchronousCommandLocked(DecoderCommand::SEEK);
+
+ if (seek_error)
+ throw std::runtime_error("Decoder failed to seek");
+}
+
+void
+DecoderControl::Quit() noexcept
+{
+ assert(thread.IsDefined());
+
+ quit = true;
+ LockAsynchronousCommand(DecoderCommand::STOP);
+
+ thread.Join();
+}
+
+void
+DecoderControl::CycleMixRamp() noexcept
+{
+ previous_mix_ramp = std::move(mix_ramp);
+ mix_ramp.Clear();
+}