From 22f0a1547c86895b4284b5fdc63ab9c82f24a442 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 4 Jan 2013 10:16:16 +0100 Subject: buffer, pipe: convert to C++ --- src/DecoderAPI.cxx | 6 +- src/DecoderControl.cxx | 5 +- src/DecoderInternal.cxx | 9 +-- src/Main.cxx | 2 +- src/MusicBuffer.cxx | 137 ++++++++++++++++++++++++++++++++++ src/MusicBuffer.hxx | 67 +++++++++++++++++ src/MusicChunk.cxx | 105 ++++++++++++++++++++++++++ src/MusicChunk.hxx | 150 +++++++++++++++++++++++++++++++++++++ src/MusicPipe.cxx | 194 ++++++++++++++++++++++++++++++++++++++++++++++++ src/MusicPipe.hxx | 112 ++++++++++++++++++++++++++++ src/OutputAll.cxx | 10 +-- src/OutputThread.cxx | 5 +- src/PlayerThread.cxx | 6 +- src/buffer.c | 137 ---------------------------------- src/buffer.h | 67 ----------------- src/chunk.c | 102 ------------------------- src/chunk.h | 151 ------------------------------------- src/crossfade.c | 2 +- src/pipe.c | 194 ------------------------------------------------ src/pipe.h | 114 ---------------------------- 20 files changed, 783 insertions(+), 792 deletions(-) create mode 100644 src/MusicBuffer.cxx create mode 100644 src/MusicBuffer.hxx create mode 100644 src/MusicChunk.cxx create mode 100644 src/MusicChunk.hxx create mode 100644 src/MusicPipe.cxx create mode 100644 src/MusicPipe.hxx delete mode 100644 src/buffer.c delete mode 100644 src/buffer.h delete mode 100644 src/chunk.c delete mode 100644 src/chunk.h delete mode 100644 src/pipe.c delete mode 100644 src/pipe.h (limited to 'src') diff --git a/src/DecoderAPI.cxx b/src/DecoderAPI.cxx index 738e71842..015d64d2b 100644 --- a/src/DecoderAPI.cxx +++ b/src/DecoderAPI.cxx @@ -22,12 +22,12 @@ extern "C" { #include "decoder_api.h" #include "audio_config.h" -#include "buffer.h" -#include "pipe.h" -#include "chunk.h" #include "replay_gain_config.h" } +#include "MusicChunk.hxx" +#include "MusicBuffer.hxx" +#include "MusicPipe.hxx" #include "DecoderControl.hxx" #include "DecoderInternal.hxx" #include "song.h" diff --git a/src/DecoderControl.cxx b/src/DecoderControl.cxx index bd075ed71..58d109483 100644 --- a/src/DecoderControl.cxx +++ b/src/DecoderControl.cxx @@ -19,12 +19,9 @@ #include "config.h" #include "DecoderControl.hxx" +#include "MusicPipe.hxx" #include "song.h" -extern "C" { -#include "pipe.h" -} - #include #undef G_LOG_DOMAIN diff --git a/src/DecoderInternal.cxx b/src/DecoderInternal.cxx index ab496dbd3..00749b899 100644 --- a/src/DecoderInternal.cxx +++ b/src/DecoderInternal.cxx @@ -20,14 +20,11 @@ #include "config.h" #include "DecoderInternal.hxx" #include "DecoderControl.hxx" - -extern "C" { -#include "pipe.h" -#include "buffer.h" -} +#include "MusicPipe.hxx" +#include "MusicBuffer.hxx" +#include "MusicChunk.hxx" #include "input_stream.h" -#include "chunk.h" #include diff --git a/src/Main.cxx b/src/Main.cxx index 1974a6103..2da1ca693 100644 --- a/src/Main.cxx +++ b/src/Main.cxx @@ -22,7 +22,7 @@ #include "CommandLine.hxx" #include "PlaylistFile.hxx" #include "UpdateGlue.hxx" -#include "chunk.h" +#include "MusicChunk.hxx" #include "StateFile.hxx" #include "PlayerThread.hxx" #include "Mapper.hxx" diff --git a/src/MusicBuffer.cxx b/src/MusicBuffer.cxx new file mode 100644 index 000000000..f1547f1f4 --- /dev/null +++ b/src/MusicBuffer.cxx @@ -0,0 +1,137 @@ +/* + * 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. + */ + +#include "config.h" +#include "MusicBuffer.hxx" +#include "MusicChunk.hxx" +#include "poison.h" + +#include + +#include + +struct music_buffer { + struct music_chunk *chunks; + unsigned num_chunks; + + struct music_chunk *available; + + /** a mutex which protects #available */ + GMutex *mutex; + +#ifndef NDEBUG + unsigned num_allocated; +#endif +}; + +struct music_buffer * +music_buffer_new(unsigned num_chunks) +{ + struct music_buffer *buffer; + struct music_chunk *chunk; + + assert(num_chunks > 0); + + buffer = g_new(struct music_buffer, 1); + + buffer->chunks = g_new(struct music_chunk, num_chunks); + buffer->num_chunks = num_chunks; + + chunk = buffer->available = buffer->chunks; + poison_undefined(chunk, sizeof(*chunk)); + + for (unsigned i = 1; i < num_chunks; ++i) { + chunk->next = &buffer->chunks[i]; + chunk = chunk->next; + poison_undefined(chunk, sizeof(*chunk)); + } + + chunk->next = NULL; + + buffer->mutex = g_mutex_new(); + +#ifndef NDEBUG + buffer->num_allocated = 0; +#endif + + return buffer; +} + +void +music_buffer_free(struct music_buffer *buffer) +{ + assert(buffer->chunks != NULL); + assert(buffer->num_chunks > 0); + assert(buffer->num_allocated == 0); + + g_mutex_free(buffer->mutex); + g_free(buffer->chunks); + g_free(buffer); +} + +unsigned +music_buffer_size(const struct music_buffer *buffer) +{ + return buffer->num_chunks; +} + +struct music_chunk * +music_buffer_allocate(struct music_buffer *buffer) +{ + struct music_chunk *chunk; + + g_mutex_lock(buffer->mutex); + + chunk = buffer->available; + if (chunk != NULL) { + buffer->available = chunk->next; + music_chunk_init(chunk); + +#ifndef NDEBUG + ++buffer->num_allocated; +#endif + } + + g_mutex_unlock(buffer->mutex); + return chunk; +} + +void +music_buffer_return(struct music_buffer *buffer, struct music_chunk *chunk) +{ + assert(buffer != NULL); + assert(chunk != NULL); + + if (chunk->other != NULL) + music_buffer_return(buffer, chunk->other); + + g_mutex_lock(buffer->mutex); + + music_chunk_free(chunk); + poison_undefined(chunk, sizeof(*chunk)); + + chunk->next = buffer->available; + buffer->available = chunk; + +#ifndef NDEBUG + --buffer->num_allocated; +#endif + + g_mutex_unlock(buffer->mutex); +} diff --git a/src/MusicBuffer.hxx b/src/MusicBuffer.hxx new file mode 100644 index 000000000..cc03dfcb3 --- /dev/null +++ b/src/MusicBuffer.hxx @@ -0,0 +1,67 @@ +/* + * 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_MUSIC_BUFFER_HXX +#define MPD_MUSIC_BUFFER_HXX + +/** + * An allocator for #music_chunk objects. + */ +struct music_buffer; + +/** + * Creates a new #music_buffer object. + * + * @param num_chunks the number of #music_chunk reserved in this + * buffer + */ +struct music_buffer * +music_buffer_new(unsigned num_chunks); + +/** + * Frees the #music_buffer object + */ +void +music_buffer_free(struct music_buffer *buffer); + +/** + * Returns the total number of reserved chunks in this buffer. This + * is the same value which was passed to the constructor + * music_buffer_new(). + */ +unsigned +music_buffer_size(const struct music_buffer *buffer); + +/** + * Allocates a chunk from the buffer. When it is not used anymore, + * call music_buffer_return(). + * + * @return an empty chunk or NULL if there are no chunks available + */ +struct music_chunk * +music_buffer_allocate(struct music_buffer *buffer); + +/** + * Returns a chunk to the buffer. It can be reused by + * music_buffer_allocate() then. + */ +void +music_buffer_return(struct music_buffer *buffer, struct music_chunk *chunk); + +#endif diff --git a/src/MusicChunk.cxx b/src/MusicChunk.cxx new file mode 100644 index 000000000..24f21f664 --- /dev/null +++ b/src/MusicChunk.cxx @@ -0,0 +1,105 @@ +/* + * 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. + */ + +#include "config.h" +#include "MusicChunk.hxx" +#include "audio_format.h" + +extern "C" { +#include "tag.h" +} + +#include + +void +music_chunk_init(struct music_chunk *chunk) +{ + chunk->other = NULL; + chunk->length = 0; + chunk->tag = NULL; + chunk->replay_gain_serial = 0; +} + +void +music_chunk_free(struct music_chunk *chunk) +{ + if (chunk->tag != NULL) + tag_free(chunk->tag); +} + +#ifndef NDEBUG +bool +music_chunk_check_format(const struct music_chunk *chunk, + const struct audio_format *audio_format) +{ + assert(chunk != NULL); + assert(audio_format != NULL); + assert(audio_format_valid(audio_format)); + + return chunk->length == 0 || + audio_format_equals(&chunk->audio_format, audio_format); +} +#endif + +void * +music_chunk_write(struct music_chunk *chunk, + const struct audio_format *audio_format, + float data_time, uint16_t bit_rate, + size_t *max_length_r) +{ + const size_t frame_size = audio_format_frame_size(audio_format); + size_t num_frames; + + assert(music_chunk_check_format(chunk, audio_format)); + assert(chunk->length == 0 || audio_format_valid(&chunk->audio_format)); + + if (chunk->length == 0) { + /* if the chunk is empty, nobody has set bitRate and + times yet */ + + chunk->bit_rate = bit_rate; + chunk->times = data_time; + } + + num_frames = (sizeof(chunk->data) - chunk->length) / frame_size; + if (num_frames == 0) + return NULL; + +#ifndef NDEBUG + chunk->audio_format = *audio_format; +#endif + + *max_length_r = num_frames * frame_size; + return chunk->data + chunk->length; +} + +bool +music_chunk_expand(struct music_chunk *chunk, + const struct audio_format *audio_format, size_t length) +{ + const size_t frame_size = audio_format_frame_size(audio_format); + + assert(chunk != NULL); + assert(chunk->length + length <= sizeof(chunk->data)); + assert(audio_format_equals(&chunk->audio_format, audio_format)); + + chunk->length += length; + + return chunk->length + frame_size > sizeof(chunk->data); +} diff --git a/src/MusicChunk.hxx b/src/MusicChunk.hxx new file mode 100644 index 000000000..0ed720064 --- /dev/null +++ b/src/MusicChunk.hxx @@ -0,0 +1,150 @@ +/* + * 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_MUSIC_CHUNK_HXX +#define MPD_MUSIC_CHUNK_HXX + +#include "replay_gain_info.h" + +#ifndef NDEBUG +#include "audio_format.h" +#endif + +#include +#include + +enum { + CHUNK_SIZE = 4096, +}; + +struct audio_format; + +/** + * A chunk of music data. Its format is defined by the + * music_pipe_append() caller. + */ +struct music_chunk { + /** the next chunk in a linked list */ + struct music_chunk *next; + + /** + * An optional chunk which should be mixed into this chunk. + * This is used for cross-fading. + */ + struct music_chunk *other; + + /** + * The current mix ratio for cross-fading: 1.0 means play 100% + * of this chunk, 0.0 means play 100% of the "other" chunk. + */ + float mix_ratio; + + /** number of bytes stored in this chunk */ + uint16_t length; + + /** current bit rate of the source file */ + uint16_t bit_rate; + + /** the time stamp within the song */ + float times; + + /** + * An optional tag associated with this chunk (and the + * following chunks); appears at song boundaries. The tag + * object is owned by this chunk, and must be freed when this + * chunk is deinitialized in music_chunk_free() + */ + struct tag *tag; + + /** + * Replay gain information associated with this chunk. + * Only valid if the serial is not 0. + */ + struct replay_gain_info replay_gain_info; + + /** + * A serial number for checking if replay gain info has + * changed since the last chunk. The magic value 0 indicates + * that there is no replay gain info available. + */ + unsigned replay_gain_serial; + + /** the data (probably PCM) */ + char data[CHUNK_SIZE]; + +#ifndef NDEBUG + struct audio_format audio_format; +#endif +}; + +void +music_chunk_init(struct music_chunk *chunk); + +void +music_chunk_free(struct music_chunk *chunk); + +static inline bool +music_chunk_is_empty(const struct music_chunk *chunk) +{ + return chunk->length == 0 && chunk->tag == NULL; +} + +#ifndef NDEBUG +/** + * Checks if the audio format if the chunk is equal to the specified + * audio_format. + */ +bool +music_chunk_check_format(const struct music_chunk *chunk, + const struct audio_format *audio_format); +#endif + +/** + * Prepares appending to the music chunk. Returns a buffer where you + * may write into. After you are finished, call music_chunk_expand(). + * + * @param chunk the music_chunk object + * @param audio_format the audio format for the appended data; must + * stay the same for the life cycle of this chunk + * @param data_time the time within the song + * @param bit_rate the current bit rate of the source file + * @param max_length_r the maximum write length is returned here + * @return a writable buffer, or NULL if the chunk is full + */ +void * +music_chunk_write(struct music_chunk *chunk, + const struct audio_format *audio_format, + float data_time, uint16_t bit_rate, + size_t *max_length_r); + +/** + * Increases the length of the chunk after the caller has written to + * the buffer returned by music_chunk_write(). + * + * @param chunk the music_chunk object + * @param audio_format the audio format for the appended data; must + * stay the same for the life cycle of this chunk + * @param length the number of bytes which were appended + * @return true if the chunk is full + */ +bool +music_chunk_expand(struct music_chunk *chunk, + const struct audio_format *audio_format, size_t length); + +#endif diff --git a/src/MusicPipe.cxx b/src/MusicPipe.cxx new file mode 100644 index 000000000..d9fc07eca --- /dev/null +++ b/src/MusicPipe.cxx @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2003-2011 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 "MusicPipe.hxx" +#include "MusicBuffer.hxx" +#include "MusicChunk.hxx" + +#include + +#include + +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 */ + GMutex *mutex; + +#ifndef NDEBUG + struct audio_format audio_format; +#endif +}; + +struct music_pipe * +music_pipe_new(void) +{ + struct music_pipe *mp = g_new(struct music_pipe, 1); + + mp->head = NULL; + mp->tail_r = &mp->head; + mp->size = 0; + mp->mutex = g_mutex_new(); + +#ifndef NDEBUG + audio_format_clear(&mp->audio_format); +#endif + + return mp; +} + +void +music_pipe_free(struct music_pipe *mp) +{ + assert(mp->head == NULL); + assert(mp->tail_r == &mp->head); + + g_mutex_free(mp->mutex); + g_free(mp); +} + +#ifndef NDEBUG + +bool +music_pipe_check_format(const struct music_pipe *pipe, + const struct audio_format *audio_format) +{ + assert(pipe != NULL); + assert(audio_format != NULL); + + return !audio_format_defined(&pipe->audio_format) || + audio_format_equals(&pipe->audio_format, audio_format); +} + +bool +music_pipe_contains(const struct music_pipe *mp, + const struct music_chunk *chunk) +{ + g_mutex_lock(mp->mutex); + + for (const struct music_chunk *i = mp->head; + i != NULL; i = i->next) { + if (i == chunk) { + g_mutex_unlock(mp->mutex); + return true; + } + } + + g_mutex_unlock(mp->mutex); + + return false; +} + +#endif + +const struct music_chunk * +music_pipe_peek(const struct music_pipe *mp) +{ + return mp->head; +} + +struct music_chunk * +music_pipe_shift(struct music_pipe *mp) +{ + struct music_chunk *chunk; + + g_mutex_lock(mp->mutex); + + chunk = mp->head; + if (chunk != NULL) { + assert(!music_chunk_is_empty(chunk)); + + mp->head = chunk->next; + --mp->size; + + if (mp->head == NULL) { + assert(mp->size == 0); + assert(mp->tail_r == &chunk->next); + + mp->tail_r = &mp->head; + } else { + assert(mp->size > 0); + assert(mp->tail_r != &chunk->next); + } + +#ifndef NDEBUG + /* poison the "next" reference */ + chunk->next = (struct music_chunk *)(void *)0x01010101; + + if (mp->size == 0) + audio_format_clear(&mp->audio_format); +#endif + } + + g_mutex_unlock(mp->mutex); + + return chunk; +} + +void +music_pipe_clear(struct music_pipe *mp, struct music_buffer *buffer) +{ + struct music_chunk *chunk; + + while ((chunk = music_pipe_shift(mp)) != NULL) + music_buffer_return(buffer, chunk); +} + +void +music_pipe_push(struct music_pipe *mp, struct music_chunk *chunk) +{ + assert(!music_chunk_is_empty(chunk)); + assert(chunk->length == 0 || audio_format_valid(&chunk->audio_format)); + + g_mutex_lock(mp->mutex); + + assert(mp->size > 0 || !audio_format_defined(&mp->audio_format)); + assert(!audio_format_defined(&mp->audio_format) || + music_chunk_check_format(chunk, &mp->audio_format)); + +#ifndef NDEBUG + if (!audio_format_defined(&mp->audio_format) && chunk->length > 0) + mp->audio_format = chunk->audio_format; +#endif + + chunk->next = NULL; + *mp->tail_r = chunk; + mp->tail_r = &chunk->next; + + ++mp->size; + + g_mutex_unlock(mp->mutex); +} + +unsigned +music_pipe_size(const struct music_pipe *mp) +{ + g_mutex_lock(mp->mutex); + unsigned size = mp->size; + g_mutex_unlock(mp->mutex); + return size; +} diff --git a/src/MusicPipe.hxx b/src/MusicPipe.hxx new file mode 100644 index 000000000..99561ca62 --- /dev/null +++ b/src/MusicPipe.hxx @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2003-2011 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_PIPE_H +#define MPD_PIPE_H + +#include "gcc.h" + +#ifndef NDEBUG +struct audio_format; +#endif + +struct music_chunk; +struct music_buffer; + +/** + * A queue of #music_chunk objects. One party appends chunks at the + * tail, and the other consumes them from the head. + */ +struct music_pipe; + +/** + * Creates a new #music_pipe object. It is empty. + */ +gcc_malloc +struct music_pipe * +music_pipe_new(void); + +/** + * Frees the object. It must be empty now. + */ +void +music_pipe_free(struct music_pipe *mp); + +#ifndef NDEBUG + +/** + * 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, + const struct audio_format *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); + +#endif + +/** + * Returns the first #music_chunk from the pipe. Returns NULL if the + * pipe is empty. + */ +gcc_pure +const struct music_chunk * +music_pipe_peek(const struct music_pipe *mp); + +/** + * 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. + * + * @param buffer the buffer object to return the chunks to + */ +void +music_pipe_clear(struct music_pipe *mp, struct music_buffer *buffer); + +/** + * Pushes a chunk to the tail of the pipe. + */ +void +music_pipe_push(struct music_pipe *mp, struct music_chunk *chunk); + +/** + * Returns the number of chunks currently in this pipe. + */ +gcc_pure +unsigned +music_pipe_size(const struct music_pipe *mp); + +gcc_pure +static inline bool +music_pipe_empty(const struct music_pipe *mp) +{ + return music_pipe_size(mp) == 0; +} + +#endif diff --git a/src/OutputAll.cxx b/src/OutputAll.cxx index ec716a411..811d93a12 100644 --- a/src/OutputAll.cxx +++ b/src/OutputAll.cxx @@ -26,21 +26,17 @@ extern "C" { #include "OutputControl.hxx" #include "OutputError.hxx" +#include "MusicBuffer.hxx" +#include "MusicPipe.hxx" +#include "MusicChunk.hxx" #include "mpd_error.h" extern "C" { #include "player_control.h" #include "conf.h" -#include "chunk.h" -#include "pipe.h" -#include "buffer.h" #include "notify.h" } -#ifndef NDEBUG -#include "chunk.h" -#endif - #include #include diff --git a/src/OutputThread.cxx b/src/OutputThread.cxx index 75394703b..e88efd389 100644 --- a/src/OutputThread.cxx +++ b/src/OutputThread.cxx @@ -23,8 +23,6 @@ extern "C" { #include "output_api.h" #include "output_internal.h" -#include "chunk.h" -#include "pipe.h" #include "player_control.h" #include "pcm_mix.h" #include "filter_plugin.h" @@ -33,6 +31,9 @@ extern "C" { #include "notify.h" } +#include "MusicPipe.hxx" +#include "MusicChunk.hxx" + #include "mpd_error.h" #include "gcc.h" diff --git a/src/PlayerThread.cxx b/src/PlayerThread.cxx index 9e5c6042b..cb641bbfb 100644 --- a/src/PlayerThread.cxx +++ b/src/PlayerThread.cxx @@ -21,6 +21,9 @@ #include "PlayerThread.hxx" #include "DecoderThread.hxx" #include "DecoderControl.hxx" +#include "MusicPipe.hxx" +#include "MusicBuffer.hxx" +#include "MusicChunk.hxx" #include "song.h" #include "Main.hxx" #include "mpd_error.h" @@ -31,10 +34,7 @@ extern "C" { #include "event_pipe.h" #include "crossfade.h" #include "tag.h" -#include "pipe.h" -#include "chunk.h" #include "idle.h" -#include "buffer.h" } #include diff --git a/src/buffer.c b/src/buffer.c deleted file mode 100644 index 559f39a9a..000000000 --- a/src/buffer.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2003-2011 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 "buffer.h" -#include "chunk.h" -#include "poison.h" - -#include - -#include - -struct music_buffer { - struct music_chunk *chunks; - unsigned num_chunks; - - struct music_chunk *available; - - /** a mutex which protects #available */ - GMutex *mutex; - -#ifndef NDEBUG - unsigned num_allocated; -#endif -}; - -struct music_buffer * -music_buffer_new(unsigned num_chunks) -{ - struct music_buffer *buffer; - struct music_chunk *chunk; - - assert(num_chunks > 0); - - buffer = g_new(struct music_buffer, 1); - - buffer->chunks = g_new(struct music_chunk, num_chunks); - buffer->num_chunks = num_chunks; - - chunk = buffer->available = buffer->chunks; - poison_undefined(chunk, sizeof(*chunk)); - - for (unsigned i = 1; i < num_chunks; ++i) { - chunk->next = &buffer->chunks[i]; - chunk = chunk->next; - poison_undefined(chunk, sizeof(*chunk)); - } - - chunk->next = NULL; - - buffer->mutex = g_mutex_new(); - -#ifndef NDEBUG - buffer->num_allocated = 0; -#endif - - return buffer; -} - -void -music_buffer_free(struct music_buffer *buffer) -{ - assert(buffer->chunks != NULL); - assert(buffer->num_chunks > 0); - assert(buffer->num_allocated == 0); - - g_mutex_free(buffer->mutex); - g_free(buffer->chunks); - g_free(buffer); -} - -unsigned -music_buffer_size(const struct music_buffer *buffer) -{ - return buffer->num_chunks; -} - -struct music_chunk * -music_buffer_allocate(struct music_buffer *buffer) -{ - struct music_chunk *chunk; - - g_mutex_lock(buffer->mutex); - - chunk = buffer->available; - if (chunk != NULL) { - buffer->available = chunk->next; - music_chunk_init(chunk); - -#ifndef NDEBUG - ++buffer->num_allocated; -#endif - } - - g_mutex_unlock(buffer->mutex); - return chunk; -} - -void -music_buffer_return(struct music_buffer *buffer, struct music_chunk *chunk) -{ - assert(buffer != NULL); - assert(chunk != NULL); - - if (chunk->other != NULL) - music_buffer_return(buffer, chunk->other); - - g_mutex_lock(buffer->mutex); - - music_chunk_free(chunk); - poison_undefined(chunk, sizeof(*chunk)); - - chunk->next = buffer->available; - buffer->available = chunk; - -#ifndef NDEBUG - --buffer->num_allocated; -#endif - - g_mutex_unlock(buffer->mutex); -} diff --git a/src/buffer.h b/src/buffer.h deleted file mode 100644 index f860231e7..000000000 --- a/src/buffer.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2003-2011 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_MUSIC_BUFFER_H -#define MPD_MUSIC_BUFFER_H - -/** - * An allocator for #music_chunk objects. - */ -struct music_buffer; - -/** - * Creates a new #music_buffer object. - * - * @param num_chunks the number of #music_chunk reserved in this - * buffer - */ -struct music_buffer * -music_buffer_new(unsigned num_chunks); - -/** - * Frees the #music_buffer object - */ -void -music_buffer_free(struct music_buffer *buffer); - -/** - * Returns the total number of reserved chunks in this buffer. This - * is the same value which was passed to the constructor - * music_buffer_new(). - */ -unsigned -music_buffer_size(const struct music_buffer *buffer); - -/** - * Allocates a chunk from the buffer. When it is not used anymore, - * call music_buffer_return(). - * - * @return an empty chunk or NULL if there are no chunks available - */ -struct music_chunk * -music_buffer_allocate(struct music_buffer *buffer); - -/** - * Returns a chunk to the buffer. It can be reused by - * music_buffer_allocate() then. - */ -void -music_buffer_return(struct music_buffer *buffer, struct music_chunk *chunk); - -#endif diff --git a/src/chunk.c b/src/chunk.c deleted file mode 100644 index 1eb96f4b9..000000000 --- a/src/chunk.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2003-2011 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 "chunk.h" -#include "audio_format.h" -#include "tag.h" - -#include - -void -music_chunk_init(struct music_chunk *chunk) -{ - chunk->other = NULL; - chunk->length = 0; - chunk->tag = NULL; - chunk->replay_gain_serial = 0; -} - -void -music_chunk_free(struct music_chunk *chunk) -{ - if (chunk->tag != NULL) - tag_free(chunk->tag); -} - -#ifndef NDEBUG -bool -music_chunk_check_format(const struct music_chunk *chunk, - const struct audio_format *audio_format) -{ - assert(chunk != NULL); - assert(audio_format != NULL); - assert(audio_format_valid(audio_format)); - - return chunk->length == 0 || - audio_format_equals(&chunk->audio_format, audio_format); -} -#endif - -void * -music_chunk_write(struct music_chunk *chunk, - const struct audio_format *audio_format, - float data_time, uint16_t bit_rate, - size_t *max_length_r) -{ - const size_t frame_size = audio_format_frame_size(audio_format); - size_t num_frames; - - assert(music_chunk_check_format(chunk, audio_format)); - assert(chunk->length == 0 || audio_format_valid(&chunk->audio_format)); - - if (chunk->length == 0) { - /* if the chunk is empty, nobody has set bitRate and - times yet */ - - chunk->bit_rate = bit_rate; - chunk->times = data_time; - } - - num_frames = (sizeof(chunk->data) - chunk->length) / frame_size; - if (num_frames == 0) - return NULL; - -#ifndef NDEBUG - chunk->audio_format = *audio_format; -#endif - - *max_length_r = num_frames * frame_size; - return chunk->data + chunk->length; -} - -bool -music_chunk_expand(struct music_chunk *chunk, - const struct audio_format *audio_format, size_t length) -{ - const size_t frame_size = audio_format_frame_size(audio_format); - - assert(chunk != NULL); - assert(chunk->length + length <= sizeof(chunk->data)); - assert(audio_format_equals(&chunk->audio_format, audio_format)); - - chunk->length += length; - - return chunk->length + frame_size > sizeof(chunk->data); -} diff --git a/src/chunk.h b/src/chunk.h deleted file mode 100644 index a06a203eb..000000000 --- a/src/chunk.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2003-2011 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_CHUNK_H -#define MPD_CHUNK_H - -#include "replay_gain_info.h" - -#ifndef NDEBUG -#include "audio_format.h" -#endif - -#include -#include -#include - -enum { - CHUNK_SIZE = 4096, -}; - -struct audio_format; - -/** - * A chunk of music data. Its format is defined by the - * music_pipe_append() caller. - */ -struct music_chunk { - /** the next chunk in a linked list */ - struct music_chunk *next; - - /** - * An optional chunk which should be mixed into this chunk. - * This is used for cross-fading. - */ - struct music_chunk *other; - - /** - * The current mix ratio for cross-fading: 1.0 means play 100% - * of this chunk, 0.0 means play 100% of the "other" chunk. - */ - float mix_ratio; - - /** number of bytes stored in this chunk */ - uint16_t length; - - /** current bit rate of the source file */ - uint16_t bit_rate; - - /** the time stamp within the song */ - float times; - - /** - * An optional tag associated with this chunk (and the - * following chunks); appears at song boundaries. The tag - * object is owned by this chunk, and must be freed when this - * chunk is deinitialized in music_chunk_free() - */ - struct tag *tag; - - /** - * Replay gain information associated with this chunk. - * Only valid if the serial is not 0. - */ - struct replay_gain_info replay_gain_info; - - /** - * A serial number for checking if replay gain info has - * changed since the last chunk. The magic value 0 indicates - * that there is no replay gain info available. - */ - unsigned replay_gain_serial; - - /** the data (probably PCM) */ - char data[CHUNK_SIZE]; - -#ifndef NDEBUG - struct audio_format audio_format; -#endif -}; - -void -music_chunk_init(struct music_chunk *chunk); - -void -music_chunk_free(struct music_chunk *chunk); - -static inline bool -music_chunk_is_empty(const struct music_chunk *chunk) -{ - return chunk->length == 0 && chunk->tag == NULL; -} - -#ifndef NDEBUG -/** - * Checks if the audio format if the chunk is equal to the specified - * audio_format. - */ -bool -music_chunk_check_format(const struct music_chunk *chunk, - const struct audio_format *audio_format); -#endif - -/** - * Prepares appending to the music chunk. Returns a buffer where you - * may write into. After you are finished, call music_chunk_expand(). - * - * @param chunk the music_chunk object - * @param audio_format the audio format for the appended data; must - * stay the same for the life cycle of this chunk - * @param data_time the time within the song - * @param bit_rate the current bit rate of the source file - * @param max_length_r the maximum write length is returned here - * @return a writable buffer, or NULL if the chunk is full - */ -void * -music_chunk_write(struct music_chunk *chunk, - const struct audio_format *audio_format, - float data_time, uint16_t bit_rate, - size_t *max_length_r); - -/** - * Increases the length of the chunk after the caller has written to - * the buffer returned by music_chunk_write(). - * - * @param chunk the music_chunk object - * @param audio_format the audio format for the appended data; must - * stay the same for the life cycle of this chunk - * @param length the number of bytes which were appended - * @return true if the chunk is full - */ -bool -music_chunk_expand(struct music_chunk *chunk, - const struct audio_format *audio_format, size_t length); - -#endif diff --git a/src/crossfade.c b/src/crossfade.c index 46a0dff30..cf3943314 100644 --- a/src/crossfade.c +++ b/src/crossfade.c @@ -19,7 +19,7 @@ #include "config.h" #include "crossfade.h" -#include "chunk.h" +#include "MusicChunk.hxx" #include "audio_format.h" #include "tag.h" diff --git a/src/pipe.c b/src/pipe.c deleted file mode 100644 index d8131432f..000000000 --- a/src/pipe.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (C) 2003-2011 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 "pipe.h" -#include "buffer.h" -#include "chunk.h" - -#include - -#include - -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 */ - GMutex *mutex; - -#ifndef NDEBUG - struct audio_format audio_format; -#endif -}; - -struct music_pipe * -music_pipe_new(void) -{ - struct music_pipe *mp = g_new(struct music_pipe, 1); - - mp->head = NULL; - mp->tail_r = &mp->head; - mp->size = 0; - mp->mutex = g_mutex_new(); - -#ifndef NDEBUG - audio_format_clear(&mp->audio_format); -#endif - - return mp; -} - -void -music_pipe_free(struct music_pipe *mp) -{ - assert(mp->head == NULL); - assert(mp->tail_r == &mp->head); - - g_mutex_free(mp->mutex); - g_free(mp); -} - -#ifndef NDEBUG - -bool -music_pipe_check_format(const struct music_pipe *pipe, - const struct audio_format *audio_format) -{ - assert(pipe != NULL); - assert(audio_format != NULL); - - return !audio_format_defined(&pipe->audio_format) || - audio_format_equals(&pipe->audio_format, audio_format); -} - -bool -music_pipe_contains(const struct music_pipe *mp, - const struct music_chunk *chunk) -{ - g_mutex_lock(mp->mutex); - - for (const struct music_chunk *i = mp->head; - i != NULL; i = i->next) { - if (i == chunk) { - g_mutex_unlock(mp->mutex); - return true; - } - } - - g_mutex_unlock(mp->mutex); - - return false; -} - -#endif - -const struct music_chunk * -music_pipe_peek(const struct music_pipe *mp) -{ - return mp->head; -} - -struct music_chunk * -music_pipe_shift(struct music_pipe *mp) -{ - struct music_chunk *chunk; - - g_mutex_lock(mp->mutex); - - chunk = mp->head; - if (chunk != NULL) { - assert(!music_chunk_is_empty(chunk)); - - mp->head = chunk->next; - --mp->size; - - if (mp->head == NULL) { - assert(mp->size == 0); - assert(mp->tail_r == &chunk->next); - - mp->tail_r = &mp->head; - } else { - assert(mp->size > 0); - assert(mp->tail_r != &chunk->next); - } - -#ifndef NDEBUG - /* poison the "next" reference */ - chunk->next = (void*)0x01010101; - - if (mp->size == 0) - audio_format_clear(&mp->audio_format); -#endif - } - - g_mutex_unlock(mp->mutex); - - return chunk; -} - -void -music_pipe_clear(struct music_pipe *mp, struct music_buffer *buffer) -{ - struct music_chunk *chunk; - - while ((chunk = music_pipe_shift(mp)) != NULL) - music_buffer_return(buffer, chunk); -} - -void -music_pipe_push(struct music_pipe *mp, struct music_chunk *chunk) -{ - assert(!music_chunk_is_empty(chunk)); - assert(chunk->length == 0 || audio_format_valid(&chunk->audio_format)); - - g_mutex_lock(mp->mutex); - - assert(mp->size > 0 || !audio_format_defined(&mp->audio_format)); - assert(!audio_format_defined(&mp->audio_format) || - music_chunk_check_format(chunk, &mp->audio_format)); - -#ifndef NDEBUG - if (!audio_format_defined(&mp->audio_format) && chunk->length > 0) - mp->audio_format = chunk->audio_format; -#endif - - chunk->next = NULL; - *mp->tail_r = chunk; - mp->tail_r = &chunk->next; - - ++mp->size; - - g_mutex_unlock(mp->mutex); -} - -unsigned -music_pipe_size(const struct music_pipe *mp) -{ - g_mutex_lock(mp->mutex); - unsigned size = mp->size; - g_mutex_unlock(mp->mutex); - return size; -} diff --git a/src/pipe.h b/src/pipe.h deleted file mode 100644 index 6b5bbf0c7..000000000 --- a/src/pipe.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2003-2011 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_PIPE_H -#define MPD_PIPE_H - -#include "gcc.h" - -#include - -#ifndef NDEBUG -struct audio_format; -#endif - -struct music_chunk; -struct music_buffer; - -/** - * A queue of #music_chunk objects. One party appends chunks at the - * tail, and the other consumes them from the head. - */ -struct music_pipe; - -/** - * Creates a new #music_pipe object. It is empty. - */ -gcc_malloc -struct music_pipe * -music_pipe_new(void); - -/** - * Frees the object. It must be empty now. - */ -void -music_pipe_free(struct music_pipe *mp); - -#ifndef NDEBUG - -/** - * 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, - const struct audio_format *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); - -#endif - -/** - * Returns the first #music_chunk from the pipe. Returns NULL if the - * pipe is empty. - */ -gcc_pure -const struct music_chunk * -music_pipe_peek(const struct music_pipe *mp); - -/** - * 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. - * - * @param buffer the buffer object to return the chunks to - */ -void -music_pipe_clear(struct music_pipe *mp, struct music_buffer *buffer); - -/** - * Pushes a chunk to the tail of the pipe. - */ -void -music_pipe_push(struct music_pipe *mp, struct music_chunk *chunk); - -/** - * Returns the number of chunks currently in this pipe. - */ -gcc_pure -unsigned -music_pipe_size(const struct music_pipe *mp); - -gcc_pure -static inline bool -music_pipe_empty(const struct music_pipe *mp) -{ - return music_pipe_size(mp) == 0; -} - -#endif -- cgit v1.2.3