Commit 3216f4b2 authored by Max Kellermann's avatar Max Kellermann

MusicBuffer: expose the C++ API

parent ce1d8975
...@@ -178,11 +178,11 @@ decoder_command_finished(struct decoder *decoder) ...@@ -178,11 +178,11 @@ decoder_command_finished(struct decoder *decoder)
/* delete frames from the old song position */ /* delete frames from the old song position */
if (decoder->chunk != NULL) { if (decoder->chunk != NULL) {
music_buffer_return(dc->buffer, decoder->chunk); dc->buffer->Return(decoder->chunk);
decoder->chunk = NULL; decoder->chunk = NULL;
} }
dc->pipe->Clear(dc->buffer); dc->pipe->Clear(*dc->buffer);
decoder->timestamp = dc->seek_where; decoder->timestamp = dc->seek_where;
} }
......
...@@ -105,10 +105,9 @@ decoder_control::IsCurrentSong(const Song *_song) const ...@@ -105,10 +105,9 @@ 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, MusicPipe &_pipe) MusicBuffer &_buffer, MusicPipe &_pipe)
{ {
assert(_song != NULL); assert(_song != NULL);
assert(_buffer != NULL);
assert(_pipe.IsEmpty()); assert(_pipe.IsEmpty());
if (song != nullptr) if (song != nullptr)
...@@ -117,7 +116,7 @@ decoder_control::Start(Song *_song, ...@@ -117,7 +116,7 @@ decoder_control::Start(Song *_song,
song = _song; 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 MusicBuffer;
class MusicPipe; class MusicPipe;
enum decoder_state { enum decoder_state {
...@@ -122,7 +123,7 @@ struct decoder_control { ...@@ -122,7 +123,7 @@ struct decoder_control {
float total_time; float total_time;
/** the #music_chunk allocator */ /** the #music_chunk allocator */
struct music_buffer *buffer; MusicBuffer *buffer;
/** /**
* The destination pipe for decoded chunks. The caller thread * The destination pipe for decoded chunks. The caller thread
...@@ -288,7 +289,7 @@ struct decoder_control { ...@@ -288,7 +289,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, MusicPipe &pipe); MusicBuffer &buffer, MusicPipe &pipe);
void Stop(); void Stop();
......
...@@ -70,7 +70,7 @@ decoder_get_chunk(struct decoder *decoder) ...@@ -70,7 +70,7 @@ decoder_get_chunk(struct decoder *decoder)
return decoder->chunk; return decoder->chunk;
do { do {
decoder->chunk = music_buffer_allocate(dc->buffer); decoder->chunk = dc->buffer->Allocate();
if (decoder->chunk != NULL) { if (decoder->chunk != NULL) {
decoder->chunk->replay_gain_serial = decoder->chunk->replay_gain_serial =
decoder->replay_gain_serial; decoder->replay_gain_serial;
...@@ -98,7 +98,7 @@ decoder_flush_chunk(struct decoder *decoder) ...@@ -98,7 +98,7 @@ decoder_flush_chunk(struct decoder *decoder)
assert(decoder->chunk != NULL); assert(decoder->chunk != NULL);
if (decoder->chunk->IsEmpty()) if (decoder->chunk->IsEmpty())
music_buffer_return(dc->buffer, decoder->chunk); dc->buffer->Return(decoder->chunk);
else else
dc->pipe->Push(decoder->chunk); dc->pipe->Push(decoder->chunk);
......
...@@ -20,60 +20,34 @@ ...@@ -20,60 +20,34 @@
#include "config.h" #include "config.h"
#include "MusicBuffer.hxx" #include "MusicBuffer.hxx"
#include "MusicChunk.hxx" #include "MusicChunk.hxx"
#include "thread/Mutex.hxx"
#include "util/SliceBuffer.hxx"
#include "system/FatalError.hxx" #include "system/FatalError.hxx"
#include <assert.h> #include <assert.h>
struct music_buffer : public SliceBuffer<music_chunk> { MusicBuffer::MusicBuffer(unsigned num_chunks)
/** a mutex which protects #available */ :buffer(num_chunks) {
Mutex mutex; if (buffer.IsOOM())
FatalError("Failed to allocate buffer");
music_buffer(unsigned num_chunks)
:SliceBuffer(num_chunks) {
if (IsOOM())
FatalError("Failed to allocate buffer");
}
};
struct music_buffer *
music_buffer_new(unsigned num_chunks)
{
return new music_buffer(num_chunks);
}
void
music_buffer_free(struct music_buffer *buffer)
{
delete buffer;
}
unsigned
music_buffer_size(const struct music_buffer *buffer)
{
return buffer->GetCapacity();
} }
struct music_chunk * music_chunk *
music_buffer_allocate(struct music_buffer *buffer) MusicBuffer::Allocate()
{ {
const ScopeLock protect(buffer->mutex); const ScopeLock protect(mutex);
return buffer->Allocate(); return buffer.Allocate();
} }
void void
music_buffer_return(struct music_buffer *buffer, struct music_chunk *chunk) MusicBuffer::Return(music_chunk *chunk)
{ {
assert(buffer != NULL); assert(chunk != nullptr);
assert(chunk != NULL);
const ScopeLock protect(buffer->mutex); const ScopeLock protect(mutex);
if (chunk->other != nullptr) { if (chunk->other != nullptr) {
assert(chunk->other->other == nullptr); assert(chunk->other->other == nullptr);
buffer->Free(chunk->other); buffer.Free(chunk->other);
} }
buffer->Free(chunk); buffer.Free(chunk);
} }
...@@ -20,48 +20,53 @@ ...@@ -20,48 +20,53 @@
#ifndef MPD_MUSIC_BUFFER_HXX #ifndef MPD_MUSIC_BUFFER_HXX
#define MPD_MUSIC_BUFFER_HXX #define MPD_MUSIC_BUFFER_HXX
#include "util/SliceBuffer.hxx"
#include "thread/Mutex.hxx"
struct music_chunk;
/** /**
* An allocator for #music_chunk objects. * An allocator for #music_chunk objects.
*/ */
struct music_buffer; class MusicBuffer {
/** a mutex which protects #buffer */
Mutex mutex;
/** SliceBuffer<music_chunk> 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);
/** public:
* Frees the #music_buffer object /**
*/ * Creates a new #MusicBuffer object.
void *
music_buffer_free(struct music_buffer *buffer); * @param num_chunks the number of #music_chunk reserved in
* this buffer
*/
MusicBuffer(unsigned num_chunks);
/** /**
* Returns the total number of reserved chunks in this buffer. This * Returns the total number of reserved chunks in this buffer. This
* is the same value which was passed to the constructor * is the same value which was passed to the constructor
* music_buffer_new(). * music_buffer_new().
*/ */
unsigned gcc_pure
music_buffer_size(const struct music_buffer *buffer); unsigned GetSize() const {
return buffer.GetCapacity();
}
/** /**
* Allocates a chunk from the buffer. When it is not used anymore, * Allocates a chunk from the buffer. When it is not used anymore,
* call music_buffer_return(). * call Return().
* *
* @return an empty chunk or NULL if there are no chunks available * @return an empty chunk or nullptr if there are no chunks
*/ * available
struct music_chunk * */
music_buffer_allocate(struct music_buffer *buffer); music_chunk *Allocate();
/** /**
* Returns a chunk to the buffer. It can be reused by * Returns a chunk to the buffer. It can be reused by
* music_buffer_allocate() then. * Allocate() then.
*/ */
void void Return(music_chunk *chunk);
music_buffer_return(struct music_buffer *buffer, struct music_chunk *chunk); };
#endif #endif
...@@ -73,12 +73,12 @@ MusicPipe::Shift() ...@@ -73,12 +73,12 @@ MusicPipe::Shift()
} }
void void
MusicPipe::Clear(music_buffer *buffer) MusicPipe::Clear(MusicBuffer &buffer)
{ {
music_chunk *chunk; music_chunk *chunk;
while ((chunk = Shift()) != nullptr) while ((chunk = Shift()) != nullptr)
music_buffer_return(buffer, chunk); buffer.Return(chunk);
} }
void void
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include <assert.h> #include <assert.h>
struct music_chunk; struct music_chunk;
struct music_buffer; class MusicBuffer;
/** /**
* A queue of #music_chunk objects. One party appends chunks at the * A queue of #music_chunk objects. One party appends chunks at the
...@@ -109,7 +109,7 @@ public: ...@@ -109,7 +109,7 @@ public:
* *
* @param buffer the buffer object to return the chunks to * @param buffer the buffer object to return the chunks to
*/ */
void Clear(music_buffer *buffer); void Clear(MusicBuffer &buffer);
/** /**
* Pushes a chunk to the tail of the pipe. * Pushes a chunk to the tail of the pipe.
......
...@@ -45,9 +45,9 @@ static struct audio_output **audio_outputs; ...@@ -45,9 +45,9 @@ static struct audio_output **audio_outputs;
static unsigned int num_audio_outputs; static unsigned int num_audio_outputs;
/** /**
* The #music_buffer object where consumed chunks are returned. * The #MusicBuffer object where consumed chunks are returned.
*/ */
static struct music_buffer *g_music_buffer; static MusicBuffer *g_music_buffer;
/** /**
* The #MusicPipe object which feeds all audio outputs. It is filled * The #MusicPipe object which feeds all audio outputs. It is filled
...@@ -302,17 +302,16 @@ audio_output_all_play(struct music_chunk *chunk, Error &error) ...@@ -302,17 +302,16 @@ audio_output_all_play(struct music_chunk *chunk, Error &error)
bool bool
audio_output_all_open(const AudioFormat audio_format, audio_output_all_open(const AudioFormat audio_format,
struct music_buffer *buffer, MusicBuffer &buffer,
Error &error) Error &error)
{ {
bool ret = false, enabled = false; bool ret = false, enabled = false;
unsigned int i; unsigned int i;
assert(buffer != NULL); assert(g_music_buffer == NULL || g_music_buffer == &buffer);
assert(g_music_buffer == NULL || g_music_buffer == buffer);
assert((g_mp == NULL) == (g_music_buffer == NULL)); assert((g_mp == NULL) == (g_music_buffer == NULL));
g_music_buffer = buffer; g_music_buffer = &buffer;
/* 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 */
...@@ -463,7 +462,7 @@ audio_output_all_check(void) ...@@ -463,7 +462,7 @@ audio_output_all_check(void)
audio_outputs[i]->mutex.unlock(); audio_outputs[i]->mutex.unlock();
/* return the chunk to the buffer */ /* return the chunk to the buffer */
music_buffer_return(g_music_buffer, shifted); g_music_buffer->Return(shifted);
} }
return 0; return 0;
...@@ -522,7 +521,7 @@ audio_output_all_cancel(void) ...@@ -522,7 +521,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)
g_mp->Clear(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 */
...@@ -545,7 +544,7 @@ audio_output_all_close(void) ...@@ -545,7 +544,7 @@ audio_output_all_close(void)
if (g_mp != NULL) { if (g_mp != NULL) {
assert(g_music_buffer != NULL); assert(g_music_buffer != NULL);
g_mp->Clear(g_music_buffer); g_mp->Clear(*g_music_buffer);
delete g_mp; delete g_mp;
g_mp = NULL; g_mp = NULL;
} }
...@@ -568,7 +567,7 @@ audio_output_all_release(void) ...@@ -568,7 +567,7 @@ audio_output_all_release(void)
if (g_mp != NULL) { if (g_mp != NULL) {
assert(g_music_buffer != NULL); assert(g_music_buffer != NULL);
g_mp->Clear(g_music_buffer); g_mp->Clear(*g_music_buffer);
delete g_mp; delete g_mp;
g_mp = NULL; g_mp = NULL;
} }
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include "replay_gain_info.h" #include "replay_gain_info.h"
struct AudioFormat; struct AudioFormat;
struct music_buffer; class MusicBuffer;
struct music_chunk; struct music_chunk;
struct player_control; struct player_control;
class Error; class Error;
...@@ -83,7 +83,7 @@ audio_output_all_enable_disable(void); ...@@ -83,7 +83,7 @@ audio_output_all_enable_disable(void);
*/ */
bool bool
audio_output_all_open(AudioFormat audio_format, audio_output_all_open(AudioFormat audio_format,
struct music_buffer *buffer, MusicBuffer &buffer,
Error &error); Error &error);
/** /**
......
...@@ -141,7 +141,7 @@ struct player { ...@@ -141,7 +141,7 @@ struct player {
elapsed_time(0.0) {} elapsed_time(0.0) {}
}; };
static struct music_buffer *player_buffer; static MusicBuffer *player_buffer;
static void static void
player_command_finished_locked(struct player_control *pc) player_command_finished_locked(struct player_control *pc)
...@@ -180,7 +180,7 @@ player_dc_start(struct player *player, MusicPipe &pipe) ...@@ -180,7 +180,7 @@ player_dc_start(struct player *player, MusicPipe &pipe)
dc->Start(pc->next_song->DupDetached(), dc->Start(pc->next_song->DupDetached(),
start_ms, pc->next_song->end_ms, start_ms, pc->next_song->end_ms,
player_buffer, pipe); *player_buffer, pipe);
} }
/** /**
...@@ -224,7 +224,7 @@ player_dc_stop(struct player *player) ...@@ -224,7 +224,7 @@ 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 */
dc->pipe->Clear(player_buffer); dc->pipe->Clear(*player_buffer);
if (dc->pipe != player->pipe) if (dc->pipe != player->pipe)
delete dc->pipe; delete dc->pipe;
...@@ -328,7 +328,7 @@ player_open_output(struct player *player) ...@@ -328,7 +328,7 @@ player_open_output(struct player *player)
pc->state == PLAYER_STATE_PAUSE); pc->state == PLAYER_STATE_PAUSE);
Error error; Error error;
if (audio_output_all_open(player->play_audio_format, player_buffer, if (audio_output_all_open(player->play_audio_format, *player_buffer,
error)) { error)) {
player->output_open = true; player->output_open = true;
player->paused = false; player->paused = false;
...@@ -441,7 +441,7 @@ player_send_silence(struct player *player) ...@@ -441,7 +441,7 @@ player_send_silence(struct player *player)
assert(player->output_open); assert(player->output_open);
assert(player->play_audio_format.IsDefined()); assert(player->play_audio_format.IsDefined());
struct music_chunk *chunk = music_buffer_allocate(player_buffer); struct music_chunk *chunk = player_buffer->Allocate();
if (chunk == NULL) { if (chunk == NULL) {
g_warning("Failed to allocate silence buffer"); g_warning("Failed to allocate silence buffer");
return false; return false;
...@@ -463,7 +463,7 @@ player_send_silence(struct player *player) ...@@ -463,7 +463,7 @@ player_send_silence(struct player *player)
Error error; Error error;
if (!audio_output_all_play(chunk, error)) { if (!audio_output_all_play(chunk, error)) {
g_warning("%s", error.GetMessage()); g_warning("%s", error.GetMessage());
music_buffer_return(player_buffer, chunk); player_buffer->Return(chunk);
return false; return false;
} }
...@@ -493,7 +493,7 @@ static bool player_seek_decoder(struct player *player) ...@@ -493,7 +493,7 @@ 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 */
player->pipe->Clear(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);
...@@ -506,7 +506,7 @@ static bool player_seek_decoder(struct player *player) ...@@ -506,7 +506,7 @@ 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 */
player->pipe->Clear(player_buffer); player->pipe->Clear(*player_buffer);
delete player->pipe; delete player->pipe;
player->pipe = dc->pipe; player->pipe = dc->pipe;
} }
...@@ -695,7 +695,7 @@ play_chunk(struct player_control *pc, ...@@ -695,7 +695,7 @@ play_chunk(struct player_control *pc,
update_song_tag(song, *chunk->tag); update_song_tag(song, *chunk->tag);
if (chunk->length == 0) { if (chunk->length == 0) {
music_buffer_return(player_buffer, chunk); player_buffer->Return(chunk);
return true; return true;
} }
...@@ -776,8 +776,7 @@ play_next_chunk(struct player *player) ...@@ -776,8 +776,7 @@ play_next_chunk(struct player *player)
beginning of the new song, we can beginning of the new song, we can
easily recover by throwing it away easily recover by throwing it away
now */ now */
music_buffer_return(player_buffer, player_buffer->Return(other_chunk);
other_chunk);
other_chunk = NULL; other_chunk = NULL;
} }
...@@ -824,7 +823,7 @@ play_next_chunk(struct player *player) ...@@ -824,7 +823,7 @@ play_next_chunk(struct player *player)
player->play_audio_format, error)) { player->play_audio_format, error)) {
g_warning("%s", error.GetMessage()); g_warning("%s", error.GetMessage());
music_buffer_return(player_buffer, chunk); player_buffer->Return(chunk);
pc->Lock(); pc->Lock();
...@@ -848,7 +847,7 @@ play_next_chunk(struct player *player) ...@@ -848,7 +847,7 @@ play_next_chunk(struct player *player)
dc->Lock(); dc->Lock();
if (!dc->IsIdle() && if (!dc->IsIdle() &&
dc->pipe->GetSize() <= (pc->buffered_before_play + dc->pipe->GetSize() <= (pc->buffered_before_play +
music_buffer_size(player_buffer) * 3) / 4) player_buffer->GetSize() * 3) / 4)
dc->Signal(); dc->Signal();
dc->Unlock(); dc->Unlock();
...@@ -1017,7 +1016,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc) ...@@ -1017,7 +1016,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
dc->mixramp_prev_end, dc->mixramp_prev_end,
dc->out_audio_format, dc->out_audio_format,
player.play_audio_format, player.play_audio_format,
music_buffer_size(player_buffer) - player_buffer->GetSize() -
pc->buffered_before_play); pc->buffered_before_play);
if (player.cross_fade_chunks > 0) { if (player.cross_fade_chunks > 0) {
player.xfade = XFADE_ENABLED; player.xfade = XFADE_ENABLED;
...@@ -1074,7 +1073,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc) ...@@ -1074,7 +1073,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
player_dc_stop(&player); player_dc_stop(&player);
player.pipe->Clear(player_buffer); player.pipe->Clear(*player_buffer);
delete player.pipe; delete player.pipe;
delete player.cross_fade_tag; delete player.cross_fade_tag;
...@@ -1107,7 +1106,7 @@ player_task(gpointer arg) ...@@ -1107,7 +1106,7 @@ player_task(gpointer arg)
struct decoder_control *dc = new decoder_control(); struct decoder_control *dc = new decoder_control();
decoder_thread_start(dc); decoder_thread_start(dc);
player_buffer = music_buffer_new(pc->buffer_chunks); player_buffer = new MusicBuffer(pc->buffer_chunks);
pc->Lock(); pc->Lock();
...@@ -1148,8 +1147,8 @@ player_task(gpointer arg) ...@@ -1148,8 +1147,8 @@ player_task(gpointer arg)
/* in the DEBUG build, check for leaked /* in the DEBUG build, check for leaked
music_chunk objects by freeing the music_chunk objects by freeing the
music_buffer */ music_buffer */
music_buffer_free(player_buffer); delete player_buffer;
player_buffer = music_buffer_new(pc->buffer_chunks); player_buffer = new MusicBuffer(pc->buffer_chunks);
#endif #endif
break; break;
...@@ -1167,7 +1166,7 @@ player_task(gpointer arg) ...@@ -1167,7 +1166,7 @@ player_task(gpointer arg)
dc->Quit(); dc->Quit();
delete dc; delete dc;
audio_output_all_close(); audio_output_all_close();
music_buffer_free(player_buffer); delete player_buffer;
player_command_finished(pc); player_command_finished(pc);
return NULL; return NULL;
......
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