Commit ce1d8975 authored by Max Kellermann's avatar Max Kellermann

MusicPipe: expose the C++ API

parent 17e108a1
...@@ -164,7 +164,7 @@ decoder_command_finished(struct decoder *decoder) ...@@ -164,7 +164,7 @@ decoder_command_finished(struct decoder *decoder)
if (decoder->initial_seek_running) { if (decoder->initial_seek_running) {
assert(!decoder->seeking); assert(!decoder->seeking);
assert(decoder->chunk == NULL); assert(decoder->chunk == NULL);
assert(music_pipe_empty(dc->pipe)); assert(dc->pipe->IsEmpty());
decoder->initial_seek_running = false; decoder->initial_seek_running = false;
decoder->timestamp = dc->start_ms / 1000.; decoder->timestamp = dc->start_ms / 1000.;
...@@ -182,7 +182,7 @@ decoder_command_finished(struct decoder *decoder) ...@@ -182,7 +182,7 @@ decoder_command_finished(struct decoder *decoder)
decoder->chunk = NULL; decoder->chunk = NULL;
} }
music_pipe_clear(dc->pipe, dc->buffer); dc->pipe->Clear(dc->buffer);
decoder->timestamp = dc->seek_where; decoder->timestamp = dc->seek_where;
} }
......
...@@ -105,12 +105,11 @@ decoder_control::IsCurrentSong(const Song *_song) const ...@@ -105,12 +105,11 @@ decoder_control::IsCurrentSong(const Song *_song) const
void void
decoder_control::Start(Song *_song, decoder_control::Start(Song *_song,
unsigned _start_ms, unsigned _end_ms, unsigned _start_ms, unsigned _end_ms,
music_buffer *_buffer, music_pipe *_pipe) music_buffer *_buffer, MusicPipe &_pipe)
{ {
assert(_song != NULL); assert(_song != NULL);
assert(_buffer != NULL); assert(_buffer != NULL);
assert(_pipe != NULL); assert(_pipe.IsEmpty());
assert(music_pipe_empty(_pipe));
if (song != nullptr) if (song != nullptr)
song->Free(); song->Free();
...@@ -119,7 +118,7 @@ decoder_control::Start(Song *_song, ...@@ -119,7 +118,7 @@ decoder_control::Start(Song *_song,
start_ms = _start_ms; start_ms = _start_ms;
end_ms = _end_ms; end_ms = _end_ms;
buffer = _buffer; buffer = _buffer;
pipe = _pipe; pipe = &_pipe;
dc_command(this, DECODE_COMMAND_START); dc_command(this, DECODE_COMMAND_START);
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <assert.h> #include <assert.h>
struct Song; struct Song;
class MusicPipe;
enum decoder_state { enum decoder_state {
DECODE_STATE_STOP = 0, DECODE_STATE_STOP = 0,
...@@ -127,7 +128,7 @@ struct decoder_control { ...@@ -127,7 +128,7 @@ struct decoder_control {
* The destination pipe for decoded chunks. The caller thread * The destination pipe for decoded chunks. The caller thread
* owns this object, and is responsible for freeing it. * owns this object, and is responsible for freeing it.
*/ */
struct music_pipe *pipe; MusicPipe *pipe;
float replay_gain_db; float replay_gain_db;
float replay_gain_prev_db; float replay_gain_prev_db;
...@@ -287,7 +288,7 @@ struct decoder_control { ...@@ -287,7 +288,7 @@ struct decoder_control {
* the caller) * the caller)
*/ */
void Start(Song *song, unsigned start_ms, unsigned end_ms, void Start(Song *song, unsigned start_ms, unsigned end_ms,
music_buffer *buffer, music_pipe *pipe); music_buffer *buffer, MusicPipe &pipe);
void Stop(); void Stop();
......
...@@ -100,7 +100,7 @@ decoder_flush_chunk(struct decoder *decoder) ...@@ -100,7 +100,7 @@ decoder_flush_chunk(struct decoder *decoder)
if (decoder->chunk->IsEmpty()) if (decoder->chunk->IsEmpty())
music_buffer_return(dc->buffer, decoder->chunk); music_buffer_return(dc->buffer, decoder->chunk);
else else
music_pipe_push(dc->pipe, decoder->chunk); dc->pipe->Push(decoder->chunk);
decoder->chunk = NULL; decoder->chunk = NULL;
} }
...@@ -36,7 +36,7 @@ struct Tag; ...@@ -36,7 +36,7 @@ struct Tag;
/** /**
* A chunk of music data. Its format is defined by the * A chunk of music data. Its format is defined by the
* music_pipe_append() caller. * MusicPipe::Push() caller.
*/ */
struct music_chunk { struct music_chunk {
/** the next chunk in a linked list */ /** the next chunk in a linked list */
......
...@@ -21,74 +21,15 @@ ...@@ -21,74 +21,15 @@
#include "MusicPipe.hxx" #include "MusicPipe.hxx"
#include "MusicBuffer.hxx" #include "MusicBuffer.hxx"
#include "MusicChunk.hxx" #include "MusicChunk.hxx"
#include "thread/Mutex.hxx"
#include <glib.h>
#include <assert.h>
struct music_pipe {
/** the first chunk */
struct music_chunk *head;
/** a pointer to the tail of the chunk */
struct music_chunk **tail_r;
/** the current number of chunks */
unsigned size;
/** a mutex which protects #head and #tail_r */
mutable Mutex mutex;
#ifndef NDEBUG #ifndef NDEBUG
AudioFormat audio_format;
#endif
music_pipe()
:head(nullptr), tail_r(&head), size(0) {
#ifndef NDEBUG
audio_format.Clear();
#endif
}
~music_pipe() {
assert(head == nullptr);
assert(tail_r == &head);
}
};
struct music_pipe *
music_pipe_new(void)
{
return new music_pipe();
}
void
music_pipe_free(struct music_pipe *mp)
{
delete mp;
}
#ifndef NDEBUG
bool
music_pipe_check_format(const struct music_pipe *pipe,
const AudioFormat audio_format)
{
assert(pipe != NULL);
return !pipe->audio_format.IsDefined() ||
pipe->audio_format == audio_format;
}
bool bool
music_pipe_contains(const struct music_pipe *mp, MusicPipe::Contains(const music_chunk *chunk) const
const struct music_chunk *chunk)
{ {
const ScopeLock protect(mp->mutex); const ScopeLock protect(mutex);
for (const struct music_chunk *i = mp->head; for (const struct music_chunk *i = head; i != nullptr; i = i->next)
i != NULL; i = i->next)
if (i == chunk) if (i == chunk)
return true; return true;
...@@ -97,40 +38,34 @@ music_pipe_contains(const struct music_pipe *mp, ...@@ -97,40 +38,34 @@ music_pipe_contains(const struct music_pipe *mp,
#endif #endif
const struct music_chunk * music_chunk *
music_pipe_peek(const struct music_pipe *mp) MusicPipe::Shift()
{
return mp->head;
}
struct music_chunk *
music_pipe_shift(struct music_pipe *mp)
{ {
const ScopeLock protect(mp->mutex); const ScopeLock protect(mutex);
struct music_chunk *chunk = mp->head; music_chunk *chunk = head;
if (chunk != NULL) { if (chunk != nullptr) {
assert(!chunk->IsEmpty()); assert(!chunk->IsEmpty());
mp->head = chunk->next; head = chunk->next;
--mp->size; --size;
if (mp->head == NULL) { if (head == nullptr) {
assert(mp->size == 0); assert(size == 0);
assert(mp->tail_r == &chunk->next); assert(tail_r == &chunk->next);
mp->tail_r = &mp->head; tail_r = &head;
} else { } else {
assert(mp->size > 0); assert(size > 0);
assert(mp->tail_r != &chunk->next); assert(tail_r != &chunk->next);
} }
#ifndef NDEBUG #ifndef NDEBUG
/* poison the "next" reference */ /* poison the "next" reference */
chunk->next = (struct music_chunk *)(void *)0x01010101; chunk->next = (music_chunk *)(void *)0x01010101;
if (mp->size == 0) if (size == 0)
mp->audio_format.Clear(); audio_format.Clear();
#endif #endif
} }
...@@ -138,41 +73,34 @@ music_pipe_shift(struct music_pipe *mp) ...@@ -138,41 +73,34 @@ music_pipe_shift(struct music_pipe *mp)
} }
void void
music_pipe_clear(struct music_pipe *mp, struct music_buffer *buffer) MusicPipe::Clear(music_buffer *buffer)
{ {
struct music_chunk *chunk; music_chunk *chunk;
while ((chunk = music_pipe_shift(mp)) != NULL) while ((chunk = Shift()) != nullptr)
music_buffer_return(buffer, chunk); music_buffer_return(buffer, chunk);
} }
void void
music_pipe_push(struct music_pipe *mp, struct music_chunk *chunk) MusicPipe::Push(music_chunk *chunk)
{ {
assert(!chunk->IsEmpty()); assert(!chunk->IsEmpty());
assert(chunk->length == 0 || chunk->audio_format.IsValid()); assert(chunk->length == 0 || chunk->audio_format.IsValid());
const ScopeLock protect(mp->mutex); const ScopeLock protect(mutex);
assert(mp->size > 0 || !mp->audio_format.IsDefined()); assert(size > 0 || !audio_format.IsDefined());
assert(!mp->audio_format.IsDefined() || assert(!audio_format.IsDefined() ||
chunk->CheckFormat(mp->audio_format)); chunk->CheckFormat(audio_format));
#ifndef NDEBUG #ifndef NDEBUG
if (!mp->audio_format.IsDefined() && chunk->length > 0) if (!audio_format.IsDefined() && chunk->length > 0)
mp->audio_format = chunk->audio_format; audio_format = chunk->audio_format;
#endif #endif
chunk->next = NULL; chunk->next = nullptr;
*mp->tail_r = chunk; *tail_r = chunk;
mp->tail_r = &chunk->next; tail_r = &chunk->next;
++mp->size;
}
unsigned ++size;
music_pipe_size(const struct music_pipe *mp)
{
const ScopeLock protect(mp->mutex);
return mp->size;
} }
...@@ -20,12 +20,15 @@ ...@@ -20,12 +20,15 @@
#ifndef MPD_PIPE_H #ifndef MPD_PIPE_H
#define MPD_PIPE_H #define MPD_PIPE_H
#include "thread/Mutex.hxx"
#include "gcc.h" #include "gcc.h"
#ifndef NDEBUG #ifndef NDEBUG
struct AudioFormat; #include "AudioFormat.hxx"
#endif #endif
#include <assert.h>
struct music_chunk; struct music_chunk;
struct music_buffer; struct music_buffer;
...@@ -33,80 +36,98 @@ struct music_buffer; ...@@ -33,80 +36,98 @@ struct music_buffer;
* A queue of #music_chunk objects. One party appends chunks at the * A queue of #music_chunk objects. One party appends chunks at the
* tail, and the other consumes them from the head. * tail, and the other consumes them from the head.
*/ */
struct music_pipe; class MusicPipe {
/** the first chunk */
music_chunk *head;
/** /** a pointer to the tail of the chunk */
* Creates a new #music_pipe object. It is empty. music_chunk **tail_r;
*/
gcc_malloc
struct music_pipe *
music_pipe_new(void);
/** /** the current number of chunks */
* Frees the object. It must be empty now. unsigned size;
*/
void
music_pipe_free(struct music_pipe *mp);
#ifndef NDEBUG /** a mutex which protects #head and #tail_r */
mutable Mutex mutex;
/**
* Checks if the audio format if the chunk is equal to the specified
* audio_format.
*/
bool
music_pipe_check_format(const struct music_pipe *pipe,
AudioFormat audio_format);
/**
* Checks if the specified chunk is enqueued in the music pipe.
*/
bool
music_pipe_contains(const struct music_pipe *mp,
const struct music_chunk *chunk);
#ifndef NDEBUG
AudioFormat audio_format;
#endif #endif
/** public:
* Returns the first #music_chunk from the pipe. Returns NULL if the /**
* pipe is empty. * Creates a new #MusicPipe object. It is empty.
*/ */
gcc_pure MusicPipe()
const struct music_chunk * :head(nullptr), tail_r(&head), size(0) {
music_pipe_peek(const struct music_pipe *mp); #ifndef NDEBUG
audio_format.Clear();
/** #endif
* Removes the first chunk from the head, and returns it. }
*/
struct music_chunk *
music_pipe_shift(struct music_pipe *mp);
/** /**
* Clears the whole pipe and returns the chunks to the buffer. * Frees the object. It must be empty now.
* */
* @param buffer the buffer object to return the chunks to ~MusicPipe() {
*/ assert(head == nullptr);
void assert(tail_r == &head);
music_pipe_clear(struct music_pipe *mp, struct music_buffer *buffer); }
/** #ifndef NDEBUG
* Pushes a chunk to the tail of the pipe. /**
*/ * Checks if the audio format if the chunk is equal to the specified
void * audio_format.
music_pipe_push(struct music_pipe *mp, struct music_chunk *chunk); */
gcc_pure
bool CheckFormat(AudioFormat other) const {
return !audio_format.IsDefined() ||
audio_format == other;
}
/**
* Checks if the specified chunk is enqueued in the music pipe.
*/
gcc_pure
bool Contains(const music_chunk *chunk) const;
#endif
/** /**
* Returns the number of chunks currently in this pipe. * Returns the first #music_chunk from the pipe. Returns
*/ * nullptr if the pipe is empty.
gcc_pure */
unsigned gcc_pure
music_pipe_size(const struct music_pipe *mp); const music_chunk *Peek() const {
return head;
gcc_pure }
static inline bool
music_pipe_empty(const struct music_pipe *mp) /**
{ * Removes the first chunk from the head, and returns it.
return music_pipe_size(mp) == 0; */
} music_chunk *Shift();
/**
* Clears the whole pipe and returns the chunks to the buffer.
*
* @param buffer the buffer object to return the chunks to
*/
void Clear(music_buffer *buffer);
/**
* Pushes a chunk to the tail of the pipe.
*/
void Push(music_chunk *chunk);
/**
* Returns the number of chunks currently in this pipe.
*/
gcc_pure
unsigned GetSize() const {
return size;
}
gcc_pure
bool IsEmpty() const {
return GetSize() == 0;
}
};
#endif #endif
...@@ -50,10 +50,10 @@ static unsigned int num_audio_outputs; ...@@ -50,10 +50,10 @@ static unsigned int num_audio_outputs;
static struct music_buffer *g_music_buffer; static struct music_buffer *g_music_buffer;
/** /**
* The #music_pipe object which feeds all audio outputs. It is filled * The #MusicPipe object which feeds all audio outputs. It is filled
* by audio_output_all_play(). * by audio_output_all_play().
*/ */
static struct music_pipe *g_mp; static MusicPipe *g_mp;
/** /**
* The "elapsed_time" stamp of the most recently finished chunk. * The "elapsed_time" stamp of the most recently finished chunk.
...@@ -262,7 +262,7 @@ audio_output_all_update(void) ...@@ -262,7 +262,7 @@ audio_output_all_update(void)
for (i = 0; i < num_audio_outputs; ++i) for (i = 0; i < num_audio_outputs; ++i)
ret = audio_output_update(audio_outputs[i], ret = audio_output_update(audio_outputs[i],
input_audio_format, g_mp) || ret; input_audio_format, *g_mp) || ret;
return ret; return ret;
} }
...@@ -292,7 +292,7 @@ audio_output_all_play(struct music_chunk *chunk, Error &error) ...@@ -292,7 +292,7 @@ audio_output_all_play(struct music_chunk *chunk, Error &error)
return false; return false;
} }
music_pipe_push(g_mp, chunk); g_mp->Push(chunk);
for (i = 0; i < num_audio_outputs; ++i) for (i = 0; i < num_audio_outputs; ++i)
audio_output_play(audio_outputs[i]); audio_output_play(audio_outputs[i]);
...@@ -316,15 +316,14 @@ audio_output_all_open(const AudioFormat audio_format, ...@@ -316,15 +316,14 @@ audio_output_all_open(const AudioFormat audio_format,
/* the audio format must be the same as existing chunks in the /* the audio format must be the same as existing chunks in the
pipe */ pipe */
assert(g_mp == NULL || music_pipe_check_format(g_mp, audio_format)); assert(g_mp == NULL || g_mp->CheckFormat(audio_format));
if (g_mp == NULL) if (g_mp == NULL)
g_mp = music_pipe_new(); g_mp = new MusicPipe();
else else
/* if the pipe hasn't been cleared, the the audio /* if the pipe hasn't been cleared, the the audio
format must not have changed */ format must not have changed */
assert(music_pipe_empty(g_mp) || assert(g_mp->IsEmpty() || audio_format == input_audio_format);
audio_format == input_audio_format);
input_audio_format = audio_format; input_audio_format = audio_format;
...@@ -366,7 +365,7 @@ chunk_is_consumed_in(const struct audio_output *ao, ...@@ -366,7 +365,7 @@ chunk_is_consumed_in(const struct audio_output *ao,
if (ao->chunk == NULL) if (ao->chunk == NULL)
return false; return false;
assert(chunk == ao->chunk || music_pipe_contains(g_mp, ao->chunk)); assert(chunk == ao->chunk || g_mp->Contains(ao->chunk));
if (chunk != ao->chunk) { if (chunk != ao->chunk) {
assert(chunk->next != NULL); assert(chunk->next != NULL);
...@@ -401,7 +400,7 @@ static void ...@@ -401,7 +400,7 @@ static void
clear_tail_chunk(gcc_unused const struct music_chunk *chunk, bool *locked) clear_tail_chunk(gcc_unused const struct music_chunk *chunk, bool *locked)
{ {
assert(chunk->next == NULL); assert(chunk->next == NULL);
assert(music_pipe_contains(g_mp, chunk)); assert(g_mp->Contains(chunk));
for (unsigned i = 0; i < num_audio_outputs; ++i) { for (unsigned i = 0; i < num_audio_outputs; ++i) {
struct audio_output *ao = audio_outputs[i]; struct audio_output *ao = audio_outputs[i];
...@@ -433,13 +432,13 @@ audio_output_all_check(void) ...@@ -433,13 +432,13 @@ audio_output_all_check(void)
assert(g_music_buffer != NULL); assert(g_music_buffer != NULL);
assert(g_mp != NULL); assert(g_mp != NULL);
while ((chunk = music_pipe_peek(g_mp)) != NULL) { while ((chunk = g_mp->Peek()) != nullptr) {
assert(!music_pipe_empty(g_mp)); assert(!g_mp->IsEmpty());
if (!chunk_is_consumed(chunk)) if (!chunk_is_consumed(chunk))
/* at least one output is not finished playing /* at least one output is not finished playing
this chunk */ this chunk */
return music_pipe_size(g_mp); return g_mp->GetSize();
if (chunk->length > 0 && chunk->times >= 0.0) if (chunk->length > 0 && chunk->times >= 0.0)
/* only update elapsed_time if the chunk /* only update elapsed_time if the chunk
...@@ -453,7 +452,7 @@ audio_output_all_check(void) ...@@ -453,7 +452,7 @@ audio_output_all_check(void)
clear_tail_chunk(chunk, locked); clear_tail_chunk(chunk, locked);
/* remove the chunk from the pipe */ /* remove the chunk from the pipe */
shifted = music_pipe_shift(g_mp); shifted = g_mp->Shift();
assert(shifted == chunk); assert(shifted == chunk);
if (is_tail) if (is_tail)
...@@ -523,7 +522,7 @@ audio_output_all_cancel(void) ...@@ -523,7 +522,7 @@ audio_output_all_cancel(void)
/* clear the music pipe and return all chunks to the buffer */ /* clear the music pipe and return all chunks to the buffer */
if (g_mp != NULL) if (g_mp != NULL)
music_pipe_clear(g_mp, g_music_buffer); g_mp->Clear(g_music_buffer);
/* the audio outputs are now waiting for a signal, to /* the audio outputs are now waiting for a signal, to
synchronize the cleared music pipe */ synchronize the cleared music pipe */
...@@ -546,8 +545,8 @@ audio_output_all_close(void) ...@@ -546,8 +545,8 @@ audio_output_all_close(void)
if (g_mp != NULL) { if (g_mp != NULL) {
assert(g_music_buffer != NULL); assert(g_music_buffer != NULL);
music_pipe_clear(g_mp, g_music_buffer); g_mp->Clear(g_music_buffer);
music_pipe_free(g_mp); delete g_mp;
g_mp = NULL; g_mp = NULL;
} }
...@@ -569,8 +568,8 @@ audio_output_all_release(void) ...@@ -569,8 +568,8 @@ audio_output_all_release(void)
if (g_mp != NULL) { if (g_mp != NULL) {
assert(g_music_buffer != NULL); assert(g_music_buffer != NULL);
music_pipe_clear(g_mp, g_music_buffer); g_mp->Clear(g_music_buffer);
music_pipe_free(g_mp); delete g_mp;
g_mp = NULL; g_mp = NULL;
} }
......
...@@ -104,7 +104,7 @@ audio_output_all_set_replay_gain_mode(enum replay_gain_mode mode); ...@@ -104,7 +104,7 @@ audio_output_all_set_replay_gain_mode(enum replay_gain_mode mode);
/** /**
* Enqueue a #music_chunk object for playing, i.e. pushes it to a * Enqueue a #music_chunk object for playing, i.e. pushes it to a
* #music_pipe. * #MusicPipe.
* *
* @param chunk the #music_chunk object to be played * @param chunk the #music_chunk object to be played
* @return true on success, false if no audio output was able to play * @return true on success, false if no audio output was able to play
...@@ -117,13 +117,13 @@ audio_output_all_play(struct music_chunk *chunk, Error &error); ...@@ -117,13 +117,13 @@ audio_output_all_play(struct music_chunk *chunk, Error &error);
* Checks if the output devices have drained their music pipe, and * Checks if the output devices have drained their music pipe, and
* returns the consumed music chunks to the #music_buffer. * returns the consumed music chunks to the #music_buffer.
* *
* @return the number of chunks to play left in the #music_pipe * @return the number of chunks to play left in the #MusicPipe
*/ */
unsigned unsigned
audio_output_all_check(void); audio_output_all_check(void);
/** /**
* Checks if the size of the #music_pipe is below the #threshold. If * Checks if the size of the #MusicPipe is below the #threshold. If
* not, it attempts to synchronize with all output threads, and waits * not, it attempts to synchronize with all output threads, and waits
* until another #music_chunk is finished. * until another #music_chunk is finished.
* *
......
...@@ -141,14 +141,13 @@ audio_output_disable(struct audio_output *ao) ...@@ -141,14 +141,13 @@ audio_output_disable(struct audio_output *ao)
static bool static bool
audio_output_open(struct audio_output *ao, audio_output_open(struct audio_output *ao,
const AudioFormat audio_format, const AudioFormat audio_format,
const struct music_pipe *mp) const MusicPipe &mp)
{ {
bool open; bool open;
assert(ao != NULL); assert(ao != NULL);
assert(ao->allow_play); assert(ao->allow_play);
assert(audio_format.IsValid()); assert(audio_format.IsValid());
assert(mp != NULL);
if (ao->fail_timer != NULL) { if (ao->fail_timer != NULL) {
g_timer_destroy(ao->fail_timer); g_timer_destroy(ao->fail_timer);
...@@ -156,12 +155,12 @@ audio_output_open(struct audio_output *ao, ...@@ -156,12 +155,12 @@ audio_output_open(struct audio_output *ao,
} }
if (ao->open && audio_format == ao->in_audio_format) { if (ao->open && audio_format == ao->in_audio_format) {
assert(ao->pipe == mp || assert(ao->pipe == &mp ||
(ao->always_on && ao->pause)); (ao->always_on && ao->pause));
if (ao->pause) { if (ao->pause) {
ao->chunk = NULL; ao->chunk = NULL;
ao->pipe = mp; ao->pipe = &mp;
/* unpause with the CANCEL command; this is a /* unpause with the CANCEL command; this is a
hack, but suits well for forcing the thread hack, but suits well for forcing the thread
...@@ -179,7 +178,7 @@ audio_output_open(struct audio_output *ao, ...@@ -179,7 +178,7 @@ audio_output_open(struct audio_output *ao,
ao->in_audio_format = audio_format; ao->in_audio_format = audio_format;
ao->chunk = NULL; ao->chunk = NULL;
ao->pipe = mp; ao->pipe = &mp;
if (ao->thread == NULL) if (ao->thread == NULL)
audio_output_thread_start(ao); audio_output_thread_start(ao);
...@@ -223,10 +222,8 @@ audio_output_close_locked(struct audio_output *ao) ...@@ -223,10 +222,8 @@ audio_output_close_locked(struct audio_output *ao)
bool bool
audio_output_update(struct audio_output *ao, audio_output_update(struct audio_output *ao,
const AudioFormat audio_format, const AudioFormat audio_format,
const struct music_pipe *mp) const MusicPipe &mp)
{ {
assert(mp != NULL);
const ScopeLock protect(ao->mutex); const ScopeLock protect(ao->mutex);
if (ao->enabled && ao->really_enabled) { if (ao->enabled && ao->really_enabled) {
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
struct audio_output; struct audio_output;
struct AudioFormat; struct AudioFormat;
struct config_param; struct config_param;
struct music_pipe; class MusicPipe;
struct player_control; struct player_control;
void void
...@@ -54,7 +54,7 @@ audio_output_disable(struct audio_output *ao); ...@@ -54,7 +54,7 @@ audio_output_disable(struct audio_output *ao);
bool bool
audio_output_update(struct audio_output *ao, audio_output_update(struct audio_output *ao,
AudioFormat audio_format, AudioFormat audio_format,
const struct music_pipe *mp); const MusicPipe &mp);
void void
audio_output_play(struct audio_output *ao); audio_output_play(struct audio_output *ao);
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
class Error; class Error;
class Filter; class Filter;
class MusicPipe;
struct config_param; struct config_param;
enum audio_output_command { enum audio_output_command {
...@@ -209,7 +210,7 @@ struct audio_output { ...@@ -209,7 +210,7 @@ struct audio_output {
/** /**
* The music pipe which provides music chunks to be played. * The music pipe which provides music chunks to be played.
*/ */
const struct music_pipe *pipe; const MusicPipe *pipe;
/** /**
* This mutex protects #open, #fail_timer, #chunk and * This mutex protects #open, #fail_timer, #chunk and
......
...@@ -263,7 +263,7 @@ ao_reopen(struct audio_output *ao) ...@@ -263,7 +263,7 @@ ao_reopen(struct audio_output *ao)
{ {
if (!ao->config_audio_format.IsFullyDefined()) { if (!ao->config_audio_format.IsFullyDefined()) {
if (ao->open) { if (ao->open) {
const struct music_pipe *mp = ao->pipe; const MusicPipe *mp = ao->pipe;
ao_close(ao, true); ao_close(ao, true);
ao->pipe = mp; ao->pipe = mp;
} }
...@@ -484,7 +484,7 @@ ao_next_chunk(struct audio_output *ao) ...@@ -484,7 +484,7 @@ ao_next_chunk(struct audio_output *ao)
/* continue the previous play() call */ /* continue the previous play() call */
? ao->chunk->next ? ao->chunk->next
/* get the first chunk from the pipe */ /* get the first chunk from the pipe */
: music_pipe_peek(ao->pipe); : ao->pipe->Peek();
} }
/** /**
...@@ -621,7 +621,7 @@ static gpointer audio_output_task(gpointer arg) ...@@ -621,7 +621,7 @@ static gpointer audio_output_task(gpointer arg)
case AO_COMMAND_DRAIN: case AO_COMMAND_DRAIN:
if (ao->open) { if (ao->open) {
assert(ao->chunk == NULL); assert(ao->chunk == NULL);
assert(music_pipe_peek(ao->pipe) == NULL); assert(ao->pipe->Peek() == nullptr);
ao->mutex.unlock(); ao->mutex.unlock();
ao_plugin_drain(ao); ao_plugin_drain(ao);
......
...@@ -54,7 +54,7 @@ struct player { ...@@ -54,7 +54,7 @@ struct player {
struct decoder_control *dc; struct decoder_control *dc;
struct music_pipe *pipe; MusicPipe *pipe;
/** /**
* are we waiting for buffered_before_play? * are we waiting for buffered_before_play?
...@@ -166,7 +166,7 @@ player_command_finished(struct player_control *pc) ...@@ -166,7 +166,7 @@ player_command_finished(struct player_control *pc)
* Player lock is not held. * Player lock is not held.
*/ */
static void static void
player_dc_start(struct player *player, struct music_pipe *pipe) player_dc_start(struct player *player, MusicPipe &pipe)
{ {
struct player_control *pc = player->pc; struct player_control *pc = player->pc;
struct decoder_control *dc = player->dc; struct decoder_control *dc = player->dc;
...@@ -224,10 +224,10 @@ player_dc_stop(struct player *player) ...@@ -224,10 +224,10 @@ player_dc_stop(struct player *player)
if (dc->pipe != NULL) { if (dc->pipe != NULL) {
/* clear and free the decoder pipe */ /* clear and free the decoder pipe */
music_pipe_clear(dc->pipe, player_buffer); dc->pipe->Clear(player_buffer);
if (dc->pipe != player->pipe) if (dc->pipe != player->pipe)
music_pipe_free(dc->pipe); delete dc->pipe;
dc->pipe = NULL; dc->pipe = NULL;
} }
...@@ -493,10 +493,10 @@ static bool player_seek_decoder(struct player *player) ...@@ -493,10 +493,10 @@ static bool player_seek_decoder(struct player *player)
/* clear music chunks which might still reside in the /* clear music chunks which might still reside in the
pipe */ pipe */
music_pipe_clear(player->pipe, player_buffer); player->pipe->Clear(player_buffer);
/* re-start the decoder */ /* re-start the decoder */
player_dc_start(player, player->pipe); player_dc_start(player, *player->pipe);
if (!player_wait_for_decoder(player)) { if (!player_wait_for_decoder(player)) {
/* decoder failure */ /* decoder failure */
player_command_finished(pc); player_command_finished(pc);
...@@ -506,8 +506,8 @@ static bool player_seek_decoder(struct player *player) ...@@ -506,8 +506,8 @@ static bool player_seek_decoder(struct player *player)
if (!player_dc_at_current_song(player)) { if (!player_dc_at_current_song(player)) {
/* the decoder is already decoding the "next" song, /* the decoder is already decoding the "next" song,
but it is the same song file; exchange the pipe */ but it is the same song file; exchange the pipe */
music_pipe_clear(player->pipe, player_buffer); player->pipe->Clear(player_buffer);
music_pipe_free(player->pipe); delete player->pipe;
player->pipe = dc->pipe; player->pipe = dc->pipe;
} }
...@@ -734,11 +734,10 @@ play_next_chunk(struct player *player) ...@@ -734,11 +734,10 @@ play_next_chunk(struct player *player)
struct music_chunk *chunk = NULL; struct music_chunk *chunk = NULL;
if (player->xfade == XFADE_ENABLED && if (player->xfade == XFADE_ENABLED &&
player_dc_at_next_song(player) && player_dc_at_next_song(player) &&
(cross_fade_position = music_pipe_size(player->pipe)) (cross_fade_position = player->pipe->GetSize())
<= player->cross_fade_chunks) { <= player->cross_fade_chunks) {
/* perform cross fade */ /* perform cross fade */
struct music_chunk *other_chunk = music_chunk *other_chunk = dc->pipe->Shift();
music_pipe_shift(dc->pipe);
if (!player->cross_fading) { if (!player->cross_fading) {
/* beginning of the cross fade - adjust /* beginning of the cross fade - adjust
...@@ -750,7 +749,7 @@ play_next_chunk(struct player *player) ...@@ -750,7 +749,7 @@ play_next_chunk(struct player *player)
} }
if (other_chunk != NULL) { if (other_chunk != NULL) {
chunk = music_pipe_shift(player->pipe); chunk = player->pipe->Shift();
assert(chunk != NULL); assert(chunk != NULL);
assert(chunk->other == NULL); assert(chunk->other == NULL);
...@@ -806,7 +805,7 @@ play_next_chunk(struct player *player) ...@@ -806,7 +805,7 @@ play_next_chunk(struct player *player)
} }
if (chunk == NULL) if (chunk == NULL)
chunk = music_pipe_shift(player->pipe); chunk = player->pipe->Shift();
assert(chunk != NULL); assert(chunk != NULL);
...@@ -848,8 +847,8 @@ play_next_chunk(struct player *player) ...@@ -848,8 +847,8 @@ play_next_chunk(struct player *player)
larger block at a time */ larger block at a time */
dc->Lock(); dc->Lock();
if (!dc->IsIdle() && if (!dc->IsIdle() &&
music_pipe_size(dc->pipe) <= (pc->buffered_before_play + dc->pipe->GetSize() <= (pc->buffered_before_play +
music_buffer_size(player_buffer) * 3) / 4) music_buffer_size(player_buffer) * 3) / 4)
dc->Signal(); dc->Signal();
dc->Unlock(); dc->Unlock();
...@@ -874,7 +873,7 @@ player_song_border(struct player *player) ...@@ -874,7 +873,7 @@ player_song_border(struct player *player)
g_message("played \"%s\"", uri); g_message("played \"%s\"", uri);
g_free(uri); g_free(uri);
music_pipe_free(player->pipe); delete player->pipe;
player->pipe = player->dc->pipe; player->pipe = player->dc->pipe;
audio_output_all_song_border(); audio_output_all_song_border();
...@@ -910,15 +909,15 @@ static void do_play(struct player_control *pc, struct decoder_control *dc) ...@@ -910,15 +909,15 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
pc->Unlock(); pc->Unlock();
player.pipe = music_pipe_new(); player.pipe = new MusicPipe();
player_dc_start(&player, player.pipe); player_dc_start(&player, *player.pipe);
if (!player_wait_for_decoder(&player)) { if (!player_wait_for_decoder(&player)) {
assert(player.song == NULL); assert(player.song == NULL);
player_dc_stop(&player); player_dc_stop(&player);
player_command_finished(pc); player_command_finished(pc);
music_pipe_free(player.pipe); delete player.pipe;
GlobalEvents::Emit(GlobalEvents::PLAYLIST); GlobalEvents::Emit(GlobalEvents::PLAYLIST);
pc->Lock(); pc->Lock();
return; return;
...@@ -949,7 +948,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc) ...@@ -949,7 +948,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
until the buffer is large enough, to until the buffer is large enough, to
prevent stuttering on slow machines */ prevent stuttering on slow machines */
if (music_pipe_size(player.pipe) < pc->buffered_before_play && if (player.pipe->GetSize() < pc->buffered_before_play &&
!dc->LockIsIdle()) { !dc->LockIsIdle()) {
/* not enough decoded buffer space yet */ /* not enough decoded buffer space yet */
...@@ -996,7 +995,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc) ...@@ -996,7 +995,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
assert(dc->pipe == NULL || dc->pipe == player.pipe); assert(dc->pipe == NULL || dc->pipe == player.pipe);
player_dc_start(&player, music_pipe_new()); player_dc_start(&player, *new MusicPipe());
} }
if (/* no cross-fading if MPD is going to pause at the if (/* no cross-fading if MPD is going to pause at the
...@@ -1035,7 +1034,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc) ...@@ -1035,7 +1034,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
if (pc->command == PLAYER_COMMAND_NONE) if (pc->command == PLAYER_COMMAND_NONE)
pc->Wait(); pc->Wait();
continue; continue;
} else if (!music_pipe_empty(player.pipe)) { } else if (!player.pipe->IsEmpty()) {
/* at least one music chunk is ready - send it /* at least one music chunk is ready - send it
to the audio output */ to the audio output */
...@@ -1056,7 +1055,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc) ...@@ -1056,7 +1055,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
/* check the size of the pipe again, because /* check the size of the pipe again, because
the decoder thread may have added something the decoder thread may have added something
since we last checked */ since we last checked */
if (music_pipe_empty(player.pipe)) { if (player.pipe->IsEmpty()) {
/* wait for the hardware to finish /* wait for the hardware to finish
playback */ playback */
audio_output_all_drain(); audio_output_all_drain();
...@@ -1075,8 +1074,8 @@ static void do_play(struct player_control *pc, struct decoder_control *dc) ...@@ -1075,8 +1074,8 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
player_dc_stop(&player); player_dc_stop(&player);
music_pipe_clear(player.pipe, player_buffer); player.pipe->Clear(player_buffer);
music_pipe_free(player.pipe); delete player.pipe;
delete player.cross_fade_tag; delete player.cross_fade_tag;
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* *
* The player thread itself does not do any I/O. It synchronizes with * The player thread itself does not do any I/O. It synchronizes with
* other threads via #GMutex and #GCond objects, and passes * other threads via #GMutex and #GCond objects, and passes
* #music_chunk instances around in #music_pipe objects. * #music_chunk instances around in #MusicPipe objects.
*/ */
#ifndef MPD_PLAYER_THREAD_HXX #ifndef MPD_PLAYER_THREAD_HXX
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment