aboutsummaryrefslogtreecommitdiff
path: root/src/DecoderControl.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/DecoderControl.hxx')
-rw-r--r--src/DecoderControl.hxx297
1 files changed, 297 insertions, 0 deletions
diff --git a/src/DecoderControl.hxx b/src/DecoderControl.hxx
new file mode 100644
index 00000000..c2d7b33a
--- /dev/null
+++ b/src/DecoderControl.hxx
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2003-2013 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.
+ */
+
+#ifndef MPD_DECODER_CONTROL_HXX
+#define MPD_DECODER_CONTROL_HXX
+
+#include "decoder_command.h"
+#include "audio_format.h"
+#include "thread/Mutex.hxx"
+#include "thread/Cond.hxx"
+
+#include <glib.h>
+
+#include <assert.h>
+
+enum decoder_state {
+ DECODE_STATE_STOP = 0,
+ DECODE_STATE_START,
+ DECODE_STATE_DECODE,
+
+ /**
+ * The last "START" command failed, because there was an I/O
+ * error or because no decoder was able to decode the file.
+ * This state will only come after START; once the state has
+ * turned to DECODE, by definition no such error can occur.
+ */
+ DECODE_STATE_ERROR,
+};
+
+struct decoder_control {
+ /** the handle of the decoder thread, or NULL if the decoder
+ thread isn't running */
+ GThread *thread;
+
+ /**
+ * This lock protects #state and #command.
+ */
+ mutable Mutex mutex;
+
+ /**
+ * Trigger this object after you have modified #command. This
+ * is also used by the decoder thread to notify the caller
+ * when it has finished a command.
+ */
+ Cond cond;
+
+ /**
+ * The trigger of this object's client. It is signalled
+ * whenever an event occurs.
+ */
+ Cond client_cond;
+
+ enum decoder_state state;
+ enum decoder_command command;
+
+ /**
+ * The error that occurred in the decoder thread. This
+ * attribute is only valid if #state is #DECODE_STATE_ERROR.
+ * The object must be freed when this object transitions to
+ * any other state (usually #DECODE_STATE_START).
+ */
+ GError *error;
+
+ bool quit;
+ bool seek_error;
+ bool seekable;
+ double seek_where;
+
+ /** the format of the song file */
+ struct audio_format in_audio_format;
+
+ /** the format being sent to the music pipe */
+ struct audio_format out_audio_format;
+
+ /**
+ * The song currently being decoded. This attribute is set by
+ * the player thread, when it sends the #DECODE_COMMAND_START
+ * command.
+ *
+ * This is a duplicate, and must be freed when this attribute
+ * is cleared.
+ */
+ struct song *song;
+
+ /**
+ * The initial seek position (in milliseconds), e.g. to the
+ * start of a sub-track described by a CUE file.
+ *
+ * This attribute is set by dc_start().
+ */
+ unsigned start_ms;
+
+ /**
+ * The decoder will stop when it reaches this position (in
+ * milliseconds). 0 means don't stop before the end of the
+ * file.
+ *
+ * This attribute is set by dc_start().
+ */
+ unsigned end_ms;
+
+ float total_time;
+
+ /** the #music_chunk allocator */
+ struct music_buffer *buffer;
+
+ /**
+ * The destination pipe for decoded chunks. The caller thread
+ * owns this object, and is responsible for freeing it.
+ */
+ struct music_pipe *pipe;
+
+ float replay_gain_db;
+ float replay_gain_prev_db;
+ char *mixramp_start;
+ char *mixramp_end;
+ char *mixramp_prev_end;
+
+ decoder_control();
+ ~decoder_control();
+
+ /**
+ * Locks the object.
+ */
+ void Lock() const {
+ mutex.lock();
+ }
+
+ /**
+ * Unlocks the object.
+ */
+ void Unlock() const {
+ mutex.unlock();
+ }
+
+ /**
+ * Signals the object. This function is only valid in the
+ * player thread. The object should be locked prior to
+ * calling this function.
+ */
+ void Signal() {
+ cond.signal();
+ }
+
+ /**
+ * Waits for a signal on the #decoder_control object. This function
+ * is only valid in the decoder thread. The object must be locked
+ * prior to calling this function.
+ */
+ void Wait() {
+ cond.wait(mutex);
+ }
+
+ /**
+ * Waits for a signal from the decoder thread. This object
+ * must be locked prior to calling this function. This method
+ * is only valid in the player thread.
+ */
+ void WaitForDecoder() {
+ client_cond.wait(mutex);
+ }
+
+ bool IsIdle() const {
+ return state == DECODE_STATE_STOP ||
+ state == DECODE_STATE_ERROR;
+ }
+
+ gcc_pure
+ bool LockIsIdle() const {
+ Lock();
+ bool result = IsIdle();
+ Unlock();
+ return result;
+ }
+
+ bool IsStarting() const {
+ return state == DECODE_STATE_START;
+ }
+
+ gcc_pure
+ bool LockIsStarting() const {
+ Lock();
+ bool result = IsStarting();
+ Unlock();
+ return result;
+ }
+
+ bool HasFailed() const {
+ assert(command == DECODE_COMMAND_NONE);
+
+ return state == DECODE_STATE_ERROR;
+ }
+
+ gcc_pure
+ bool LockHasFailed() const {
+ Lock();
+ bool result = HasFailed();
+ Unlock();
+ return result;
+ }
+
+ /**
+ * Checks whether an error has occurred, and if so, returns a newly
+ * allocated copy of the #GError object.
+ *
+ * Caller must lock the object.
+ */
+ GError *GetError() const {
+ assert(command == DECODE_COMMAND_NONE);
+ assert(state != DECODE_STATE_ERROR || error != nullptr);
+
+ return state == DECODE_STATE_ERROR
+ ? g_error_copy(error)
+ : nullptr;
+ }
+
+ /**
+ * Like dc_get_error(), but locks and unlocks the object.
+ */
+ GError *LockGetError() const {
+ Lock();
+ GError *result = GetError();
+ Unlock();
+ return result;
+ }
+
+ /**
+ * Clear the error condition and free the #GError object (if any).
+ *
+ * Caller must lock the object.
+ */
+ void ClearError() {
+ if (state == DECODE_STATE_ERROR) {
+ g_error_free(error);
+ state = DECODE_STATE_STOP;
+ }
+ }
+
+ /**
+ * Check if the specified song is currently being decoded. If the
+ * decoder is not running currently (or being started), then this
+ * function returns false in any case.
+ *
+ * Caller must lock the object.
+ */
+ gcc_pure
+ bool IsCurrentSong(const struct song *_song) const;
+
+ gcc_pure
+ bool LockIsCurrentSong(const struct song *_song) const {
+ Lock();
+ const bool result = IsCurrentSong(_song);
+ Unlock();
+ return result;
+ }
+
+ /**
+ * Start the decoder.
+ *
+ * @param song the song to be decoded; the given instance will be
+ * owned and freed by the decoder
+ * @param start_ms see #decoder_control
+ * @param end_ms see #decoder_control
+ * @param pipe the pipe which receives the decoded chunks (owned by
+ * the caller)
+ */
+ void Start(struct song *song, unsigned start_ms, unsigned end_ms,
+ music_buffer *buffer, music_pipe *pipe);
+
+ void Stop();
+
+ bool Seek(double where);
+
+ void Quit();
+
+ void MixRampStart(char *_mixramp_start);
+ void MixRampEnd(char *_mixramp_end);
+ void MixRampPrevEnd(char *_mixramp_prev_end);
+};
+
+#endif