From 767b4c95bdb468429232a96242bd73b8e92d8660 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 2 Nov 2008 14:12:52 +0100 Subject: renamed outputBuffer.[ch] to pipe.[ch] No CamelCase in the file name. The output_buffer struct is going to be renamed to music_pipe. There are so many buffer levels in MPD, and calling this one "output buffer" is wrong, because it's not the last buffer before the music reaches the output devices. --- src/Makefile.am | 4 +- src/crossfade.h | 2 +- src/decoder_api.c | 2 +- src/decoder_thread.c | 2 +- src/main.c | 2 +- src/outputBuffer.c | 228 --------------------------------------------------- src/outputBuffer.h | 115 -------------------------- src/pipe.c | 228 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/pipe.h | 115 ++++++++++++++++++++++++++ src/playerData.c | 2 +- 10 files changed, 350 insertions(+), 350 deletions(-) delete mode 100644 src/outputBuffer.c delete mode 100644 src/outputBuffer.h create mode 100644 src/pipe.c create mode 100644 src/pipe.h diff --git a/src/Makefile.am b/src/Makefile.am index 56651e36f..8debfb6a7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,7 +45,7 @@ mpd_headers = \ normalize.h \ compress.h \ os_compat.h \ - outputBuffer.h \ + pipe.h \ path.h \ mapper.h \ pcm_utils.h \ @@ -124,7 +124,7 @@ mpd_SOURCES = \ main_notify.c \ normalize.c \ compress.c \ - outputBuffer.c \ + pipe.c \ path.c \ mapper.c \ pcm_utils.c \ diff --git a/src/crossfade.h b/src/crossfade.h index a8b6e85ad..5ceb37b11 100644 --- a/src/crossfade.h +++ b/src/crossfade.h @@ -20,7 +20,7 @@ #ifndef MPD_CROSSFADE_H #define MPD_CROSSFADE_H -#include "outputBuffer.h" +#include "pipe.h" struct audio_format; diff --git a/src/decoder_api.c b/src/decoder_api.c index 77f5b0215..1c9bd822a 100644 --- a/src/decoder_api.c +++ b/src/decoder_api.c @@ -25,7 +25,7 @@ #include "utils.h" #include "normalize.h" -#include "outputBuffer.h" +#include "pipe.h" #include "gcc.h" #include diff --git a/src/decoder_thread.c b/src/decoder_thread.c index 659d43603..f45446dc2 100644 --- a/src/decoder_thread.c +++ b/src/decoder_thread.c @@ -21,7 +21,7 @@ #include "decoder_control.h" #include "decoder_internal.h" #include "player_control.h" -#include "outputBuffer.h" +#include "pipe.h" #include "song.h" #include "mapper.h" #include "path.h" diff --git a/src/main.c b/src/main.c index 025570f84..5b50b135d 100644 --- a/src/main.c +++ b/src/main.c @@ -28,7 +28,7 @@ #include "path.h" #include "mapper.h" #include "playerData.h" -#include "outputBuffer.h" +#include "pipe.h" #include "decoder_thread.h" #include "decoder_control.h" #include "player_control.h" diff --git a/src/outputBuffer.c b/src/outputBuffer.c deleted file mode 100644 index 932ffd032..000000000 --- a/src/outputBuffer.c +++ /dev/null @@ -1,228 +0,0 @@ -/* the Music Player Daemon (MPD) - * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) - * This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "outputBuffer.h" -#include "notify.h" -#include "utils.h" - -#include -#include - -struct output_buffer ob; - -void -ob_init(unsigned int size, struct notify *notify) -{ - assert(size > 0); - - ob.chunks = xmalloc(size * sizeof(*ob.chunks)); - ob.size = size; - ob.begin = 0; - ob.end = 0; - ob.lazy = false; - ob.notify = notify; - ob.chunks[0].chunkSize = 0; -} - -void ob_free(void) -{ - assert(ob.chunks != NULL); - free(ob.chunks); -} - -void ob_clear(void) -{ - ob.end = ob.begin; - ob.chunks[ob.end].chunkSize = 0; -} - -/** return the index of the chunk after i */ -static inline unsigned successor(unsigned i) -{ - assert(i <= ob.size); - - ++i; - return i == ob.size ? 0 : i; -} - -/** - * Mark the tail chunk as "full" and wake up the player if is waiting - * for the decoder. - */ -static void output_buffer_expand(unsigned i) -{ - int was_empty = ob.notify != NULL && (!ob.lazy || ob_is_empty()); - - assert(i == (ob.end + 1) % ob.size); - assert(i != ob.end); - - ob.end = i; - ob.chunks[i].chunkSize = 0; - if (was_empty) - /* if the buffer was empty, the player thread might be - waiting for us; wake it up now that another decoded - buffer has become available. */ - notify_signal(ob.notify); -} - -void ob_flush(void) -{ - ob_chunk *chunk = ob_get_chunk(ob.end); - - if (chunk->chunkSize > 0) { - unsigned int next = successor(ob.end); - if (next == ob.begin) - /* all buffers are full; we have to wait for - the player to free one, so don't flush - right now */ - return; - - output_buffer_expand(next); - } -} - -void ob_set_lazy(bool lazy) -{ - ob.lazy = lazy; -} - -void ob_shift(void) -{ - assert(ob.begin != ob.end); - assert(ob.begin < ob.size); - - ob.begin = successor(ob.begin); -} - -unsigned int ob_relative(const unsigned i) -{ - if (i >= ob.begin) - return i - ob.begin; - else - return i + ob.size - ob.begin; -} - -unsigned ob_available(void) -{ - return ob_relative(ob.end); -} - -int ob_absolute(const unsigned relative) -{ - unsigned i, max; - - max = ob.end; - if (max < ob.begin) - max += ob.size; - i = (unsigned)ob.begin + relative; - if (i >= max) - return -1; - - if (i >= ob.size) - i -= ob.size; - - return (int)i; -} - -ob_chunk * ob_get_chunk(const unsigned i) -{ - assert(i < ob.size); - - return &ob.chunks[i]; -} - -/** - * Return the tail chunk which has room for additional data. - * - * @return the chunk which has room for more data; NULL if there is no - * room. - */ -static ob_chunk *tail_chunk(float data_time, uint16_t bitRate) -{ - const size_t frame_size = audio_format_frame_size(&ob.audioFormat); - unsigned int next; - ob_chunk *chunk; - - chunk = ob_get_chunk(ob.end); - assert(chunk->chunkSize <= sizeof(chunk->data)); - if (chunk->chunkSize + frame_size > sizeof(chunk->data)) { - /* this chunk is full; allocate a new chunk */ - next = successor(ob.end); - if (ob.begin == next) - /* no chunks available */ - return NULL; - - output_buffer_expand(next); - chunk = ob_get_chunk(next); - assert(chunk->chunkSize == 0); - } - - if (chunk->chunkSize == 0) { - /* if the chunk is empty, nobody has set bitRate and - times yet */ - - chunk->bitRate = bitRate; - chunk->times = data_time; - } - - return chunk; -} - -size_t ob_append(const void *data0, size_t datalen, - float data_time, uint16_t bitRate) -{ - const unsigned char *data = data0; - const size_t frame_size = audio_format_frame_size(&ob.audioFormat); - size_t ret = 0, dataToSend; - ob_chunk *chunk = NULL; - - /* no partial frames allowed */ - assert((datalen % frame_size) == 0); - - while (datalen) { - chunk = tail_chunk(data_time, bitRate); - if (chunk == NULL) - return ret; - - dataToSend = sizeof(chunk->data) - chunk->chunkSize; - if (dataToSend > datalen) - dataToSend = datalen; - - /* don't split frames */ - dataToSend /= frame_size; - dataToSend *= frame_size; - - memcpy(chunk->data + chunk->chunkSize, data, dataToSend); - chunk->chunkSize += dataToSend; - datalen -= dataToSend; - data += dataToSend; - ret += dataToSend; - } - - if (chunk != NULL && chunk->chunkSize == sizeof(chunk->data)) - ob_flush(); - - return ret; -} - -void ob_skip(unsigned num) -{ - int i = ob_absolute(num); - if (i >= 0) - ob.begin = i; -} diff --git a/src/outputBuffer.h b/src/outputBuffer.h deleted file mode 100644 index 4769abc19..000000000 --- a/src/outputBuffer.h +++ /dev/null @@ -1,115 +0,0 @@ -/* the Music Player Daemon (MPD) - * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) - * This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef MPD_OUTPUT_BUFFER_H -#define MPD_OUTPUT_BUFFER_H - -#include "audio_format.h" - -#include -#include - -/* pick 1020 since its devisible for 8,16,24, and 32-bit audio */ -#define CHUNK_SIZE 1020 - -typedef struct _OutputBufferChunk { - uint16_t chunkSize; - uint16_t bitRate; - float times; - char data[CHUNK_SIZE]; -} ob_chunk; - -/** - * A ring set of buffers where the decoder appends data after the end, - * and the player consumes data from the beginning. - */ -struct output_buffer { - ob_chunk *chunks; - - unsigned int size; - - /** the index of the first decoded chunk */ - unsigned int volatile begin; - - /** the index after the last decoded chunk */ - unsigned int volatile end; - - /** non-zero if the player thread should only we woken up if - the buffer becomes non-empty */ - bool lazy; - - struct audio_format audioFormat; - - struct notify *notify; -}; - -extern struct output_buffer ob; - -void -ob_init(unsigned int size, struct notify *notify); - -void ob_free(void); - -void ob_clear(void); - -void ob_flush(void); - -/** - * When a chunk is decoded, we wake up the player thread to tell him - * about it. In "lazy" mode, we only wake him up when the buffer was - * previously empty, i.e. when the player thread has really been - * waiting for us. - */ -void ob_set_lazy(bool lazy); - -/** is the buffer empty? */ -static inline bool ob_is_empty(void) -{ - return ob.begin == ob.end; -} - -void ob_shift(void); - -/** - * what is the position of the specified chunk number, relative to - * the first chunk in use? - */ -unsigned int ob_relative(const unsigned i); - -/** determine the number of decoded chunks */ -unsigned ob_available(void); - -/** - * Get the absolute index of the nth used chunk after the first one. - * Returns -1 if there is no such chunk. - */ -int ob_absolute(const unsigned relative); - -ob_chunk * ob_get_chunk(const unsigned i); - -/** - * Append a data block to the buffer. - * - * @return the number of bytes actually written - */ -size_t ob_append(const void *data, size_t datalen, - float data_time, uint16_t bitRate); - -void ob_skip(unsigned num); - -#endif diff --git a/src/pipe.c b/src/pipe.c new file mode 100644 index 000000000..9b8683834 --- /dev/null +++ b/src/pipe.c @@ -0,0 +1,228 @@ +/* the Music Player Daemon (MPD) + * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) + * This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "pipe.h" +#include "notify.h" +#include "utils.h" + +#include +#include + +struct output_buffer ob; + +void +ob_init(unsigned int size, struct notify *notify) +{ + assert(size > 0); + + ob.chunks = xmalloc(size * sizeof(*ob.chunks)); + ob.size = size; + ob.begin = 0; + ob.end = 0; + ob.lazy = false; + ob.notify = notify; + ob.chunks[0].chunkSize = 0; +} + +void ob_free(void) +{ + assert(ob.chunks != NULL); + free(ob.chunks); +} + +void ob_clear(void) +{ + ob.end = ob.begin; + ob.chunks[ob.end].chunkSize = 0; +} + +/** return the index of the chunk after i */ +static inline unsigned successor(unsigned i) +{ + assert(i <= ob.size); + + ++i; + return i == ob.size ? 0 : i; +} + +/** + * Mark the tail chunk as "full" and wake up the player if is waiting + * for the decoder. + */ +static void output_buffer_expand(unsigned i) +{ + int was_empty = ob.notify != NULL && (!ob.lazy || ob_is_empty()); + + assert(i == (ob.end + 1) % ob.size); + assert(i != ob.end); + + ob.end = i; + ob.chunks[i].chunkSize = 0; + if (was_empty) + /* if the buffer was empty, the player thread might be + waiting for us; wake it up now that another decoded + buffer has become available. */ + notify_signal(ob.notify); +} + +void ob_flush(void) +{ + ob_chunk *chunk = ob_get_chunk(ob.end); + + if (chunk->chunkSize > 0) { + unsigned int next = successor(ob.end); + if (next == ob.begin) + /* all buffers are full; we have to wait for + the player to free one, so don't flush + right now */ + return; + + output_buffer_expand(next); + } +} + +void ob_set_lazy(bool lazy) +{ + ob.lazy = lazy; +} + +void ob_shift(void) +{ + assert(ob.begin != ob.end); + assert(ob.begin < ob.size); + + ob.begin = successor(ob.begin); +} + +unsigned int ob_relative(const unsigned i) +{ + if (i >= ob.begin) + return i - ob.begin; + else + return i + ob.size - ob.begin; +} + +unsigned ob_available(void) +{ + return ob_relative(ob.end); +} + +int ob_absolute(const unsigned relative) +{ + unsigned i, max; + + max = ob.end; + if (max < ob.begin) + max += ob.size; + i = (unsigned)ob.begin + relative; + if (i >= max) + return -1; + + if (i >= ob.size) + i -= ob.size; + + return (int)i; +} + +ob_chunk * ob_get_chunk(const unsigned i) +{ + assert(i < ob.size); + + return &ob.chunks[i]; +} + +/** + * Return the tail chunk which has room for additional data. + * + * @return the chunk which has room for more data; NULL if there is no + * room. + */ +static ob_chunk *tail_chunk(float data_time, uint16_t bitRate) +{ + const size_t frame_size = audio_format_frame_size(&ob.audioFormat); + unsigned int next; + ob_chunk *chunk; + + chunk = ob_get_chunk(ob.end); + assert(chunk->chunkSize <= sizeof(chunk->data)); + if (chunk->chunkSize + frame_size > sizeof(chunk->data)) { + /* this chunk is full; allocate a new chunk */ + next = successor(ob.end); + if (ob.begin == next) + /* no chunks available */ + return NULL; + + output_buffer_expand(next); + chunk = ob_get_chunk(next); + assert(chunk->chunkSize == 0); + } + + if (chunk->chunkSize == 0) { + /* if the chunk is empty, nobody has set bitRate and + times yet */ + + chunk->bitRate = bitRate; + chunk->times = data_time; + } + + return chunk; +} + +size_t ob_append(const void *data0, size_t datalen, + float data_time, uint16_t bitRate) +{ + const unsigned char *data = data0; + const size_t frame_size = audio_format_frame_size(&ob.audioFormat); + size_t ret = 0, dataToSend; + ob_chunk *chunk = NULL; + + /* no partial frames allowed */ + assert((datalen % frame_size) == 0); + + while (datalen) { + chunk = tail_chunk(data_time, bitRate); + if (chunk == NULL) + return ret; + + dataToSend = sizeof(chunk->data) - chunk->chunkSize; + if (dataToSend > datalen) + dataToSend = datalen; + + /* don't split frames */ + dataToSend /= frame_size; + dataToSend *= frame_size; + + memcpy(chunk->data + chunk->chunkSize, data, dataToSend); + chunk->chunkSize += dataToSend; + datalen -= dataToSend; + data += dataToSend; + ret += dataToSend; + } + + if (chunk != NULL && chunk->chunkSize == sizeof(chunk->data)) + ob_flush(); + + return ret; +} + +void ob_skip(unsigned num) +{ + int i = ob_absolute(num); + if (i >= 0) + ob.begin = i; +} diff --git a/src/pipe.h b/src/pipe.h new file mode 100644 index 000000000..477b1e358 --- /dev/null +++ b/src/pipe.h @@ -0,0 +1,115 @@ +/* the Music Player Daemon (MPD) + * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) + * This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MPD_PIPE_H +#define MPD_PIPE_H + +#include "audio_format.h" + +#include +#include + +/* pick 1020 since its devisible for 8,16,24, and 32-bit audio */ +#define CHUNK_SIZE 1020 + +typedef struct _OutputBufferChunk { + uint16_t chunkSize; + uint16_t bitRate; + float times; + char data[CHUNK_SIZE]; +} ob_chunk; + +/** + * A ring set of buffers where the decoder appends data after the end, + * and the player consumes data from the beginning. + */ +struct output_buffer { + ob_chunk *chunks; + + unsigned int size; + + /** the index of the first decoded chunk */ + unsigned int volatile begin; + + /** the index after the last decoded chunk */ + unsigned int volatile end; + + /** non-zero if the player thread should only we woken up if + the buffer becomes non-empty */ + bool lazy; + + struct audio_format audioFormat; + + struct notify *notify; +}; + +extern struct output_buffer ob; + +void +ob_init(unsigned int size, struct notify *notify); + +void ob_free(void); + +void ob_clear(void); + +void ob_flush(void); + +/** + * When a chunk is decoded, we wake up the player thread to tell him + * about it. In "lazy" mode, we only wake him up when the buffer was + * previously empty, i.e. when the player thread has really been + * waiting for us. + */ +void ob_set_lazy(bool lazy); + +/** is the buffer empty? */ +static inline bool ob_is_empty(void) +{ + return ob.begin == ob.end; +} + +void ob_shift(void); + +/** + * what is the position of the specified chunk number, relative to + * the first chunk in use? + */ +unsigned int ob_relative(const unsigned i); + +/** determine the number of decoded chunks */ +unsigned ob_available(void); + +/** + * Get the absolute index of the nth used chunk after the first one. + * Returns -1 if there is no such chunk. + */ +int ob_absolute(const unsigned relative); + +ob_chunk * ob_get_chunk(const unsigned i); + +/** + * Append a data block to the buffer. + * + * @return the number of bytes actually written + */ +size_t ob_append(const void *data, size_t datalen, + float data_time, uint16_t bitRate); + +void ob_skip(unsigned num); + +#endif diff --git a/src/playerData.c b/src/playerData.c index fd87843ab..2731e916b 100644 --- a/src/playerData.c +++ b/src/playerData.c @@ -17,7 +17,7 @@ */ #include "playerData.h" -#include "outputBuffer.h" +#include "pipe.h" #include "conf.h" #include "log.h" -- cgit v1.2.3