DecoderControl: move functions into the class
This commit is contained in:
parent
e1b03b4a71
commit
32799fef5c
@ -64,10 +64,10 @@ decoder_initialized(struct decoder *decoder,
|
|||||||
dc->seekable = seekable;
|
dc->seekable = seekable;
|
||||||
dc->total_time = total_time;
|
dc->total_time = total_time;
|
||||||
|
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
dc->state = DECODE_STATE_DECODE;
|
dc->state = DECODE_STATE_DECODE;
|
||||||
g_cond_signal(dc->client_cond);
|
g_cond_signal(dc->client_cond);
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
g_debug("audio_format=%s, seekable=%s",
|
g_debug("audio_format=%s, seekable=%s",
|
||||||
audio_format_to_string(&dc->in_audio_format, &af_string),
|
audio_format_to_string(&dc->in_audio_format, &af_string),
|
||||||
@ -155,7 +155,7 @@ decoder_command_finished(struct decoder *decoder)
|
|||||||
{
|
{
|
||||||
struct decoder_control *dc = decoder->dc;
|
struct decoder_control *dc = decoder->dc;
|
||||||
|
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
|
|
||||||
assert(dc->command != DECODE_COMMAND_NONE ||
|
assert(dc->command != DECODE_COMMAND_NONE ||
|
||||||
decoder->initial_seek_running);
|
decoder->initial_seek_running);
|
||||||
@ -171,7 +171,7 @@ decoder_command_finished(struct decoder *decoder)
|
|||||||
|
|
||||||
decoder->initial_seek_running = false;
|
decoder->initial_seek_running = false;
|
||||||
decoder->timestamp = dc->start_ms / 1000.;
|
decoder->timestamp = dc->start_ms / 1000.;
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ decoder_command_finished(struct decoder *decoder)
|
|||||||
|
|
||||||
dc->command = DECODE_COMMAND_NONE;
|
dc->command = DECODE_COMMAND_NONE;
|
||||||
g_cond_signal(dc->client_cond);
|
g_cond_signal(dc->client_cond);
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
double decoder_seek_where(G_GNUC_UNUSED struct decoder * decoder)
|
double decoder_seek_where(G_GNUC_UNUSED struct decoder * decoder)
|
||||||
@ -377,9 +377,9 @@ decoder_data(struct decoder *decoder,
|
|||||||
assert(dc->pipe != NULL);
|
assert(dc->pipe != NULL);
|
||||||
assert(length % audio_format_frame_size(&dc->in_audio_format) == 0);
|
assert(length % audio_format_frame_size(&dc->in_audio_format) == 0);
|
||||||
|
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
cmd = decoder_get_virtual_command(decoder);
|
cmd = decoder_get_virtual_command(decoder);
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
if (cmd == DECODE_COMMAND_STOP || cmd == DECODE_COMMAND_SEEK ||
|
if (cmd == DECODE_COMMAND_STOP || cmd == DECODE_COMMAND_SEEK ||
|
||||||
length == 0)
|
length == 0)
|
||||||
@ -564,6 +564,6 @@ decoder_mixramp(struct decoder *decoder,
|
|||||||
struct decoder_control *dc = decoder->dc;
|
struct decoder_control *dc = decoder->dc;
|
||||||
assert(dc != NULL);
|
assert(dc != NULL);
|
||||||
|
|
||||||
dc_mixramp_start(dc, mixramp_start);
|
dc->MixRampStart(mixramp_start);
|
||||||
dc_mixramp_end(dc, mixramp_end);
|
dc->MixRampEnd(mixramp_end);
|
||||||
}
|
}
|
||||||
|
@ -27,46 +27,30 @@
|
|||||||
#undef G_LOG_DOMAIN
|
#undef G_LOG_DOMAIN
|
||||||
#define G_LOG_DOMAIN "decoder_control"
|
#define G_LOG_DOMAIN "decoder_control"
|
||||||
|
|
||||||
struct decoder_control *
|
decoder_control::decoder_control()
|
||||||
dc_new()
|
:thread(nullptr),
|
||||||
|
mutex(g_mutex_new()), cond(g_cond_new()),
|
||||||
|
client_cond(g_cond_new()),
|
||||||
|
state(DECODE_STATE_STOP),
|
||||||
|
command(DECODE_COMMAND_NONE),
|
||||||
|
song(nullptr),
|
||||||
|
replay_gain_db(0), replay_gain_prev_db(0),
|
||||||
|
mixramp_start(nullptr), mixramp_end(nullptr),
|
||||||
|
mixramp_prev_end(nullptr) {}
|
||||||
|
|
||||||
|
decoder_control::~decoder_control()
|
||||||
{
|
{
|
||||||
struct decoder_control *dc = g_new(struct decoder_control, 1);
|
ClearError();
|
||||||
|
|
||||||
dc->thread = NULL;
|
if (song != NULL)
|
||||||
|
song_free(song);
|
||||||
|
|
||||||
dc->mutex = g_mutex_new();
|
g_cond_free(client_cond);
|
||||||
dc->cond = g_cond_new();
|
g_cond_free(cond);
|
||||||
dc->client_cond = g_cond_new();
|
g_mutex_free(mutex);
|
||||||
|
g_free(mixramp_start);
|
||||||
dc->state = DECODE_STATE_STOP;
|
g_free(mixramp_end);
|
||||||
dc->command = DECODE_COMMAND_NONE;
|
g_free(mixramp_prev_end);
|
||||||
|
|
||||||
dc->song = NULL;
|
|
||||||
|
|
||||||
dc->replay_gain_db = 0;
|
|
||||||
dc->replay_gain_prev_db = 0;
|
|
||||||
dc->mixramp_start = NULL;
|
|
||||||
dc->mixramp_end = NULL;
|
|
||||||
dc->mixramp_prev_end = NULL;
|
|
||||||
|
|
||||||
return dc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
dc_free(struct decoder_control *dc)
|
|
||||||
{
|
|
||||||
dc_clear_error(dc);
|
|
||||||
|
|
||||||
if (dc->song != NULL)
|
|
||||||
song_free(dc->song);
|
|
||||||
|
|
||||||
g_cond_free(dc->client_cond);
|
|
||||||
g_cond_free(dc->cond);
|
|
||||||
g_mutex_free(dc->mutex);
|
|
||||||
g_free(dc->mixramp_start);
|
|
||||||
g_free(dc->mixramp_end);
|
|
||||||
g_free(dc->mixramp_prev_end);
|
|
||||||
g_free(dc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -80,45 +64,43 @@ static void
|
|||||||
dc_command_locked(struct decoder_control *dc, enum decoder_command cmd)
|
dc_command_locked(struct decoder_control *dc, enum decoder_command cmd)
|
||||||
{
|
{
|
||||||
dc->command = cmd;
|
dc->command = cmd;
|
||||||
decoder_signal(dc);
|
dc->Signal();
|
||||||
dc_command_wait_locked(dc);
|
dc_command_wait_locked(dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dc_command(struct decoder_control *dc, enum decoder_command cmd)
|
dc_command(struct decoder_control *dc, enum decoder_command cmd)
|
||||||
{
|
{
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
dc_clear_error(dc);
|
dc->ClearError();
|
||||||
dc_command_locked(dc, cmd);
|
dc_command_locked(dc, cmd);
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dc_command_async(struct decoder_control *dc, enum decoder_command cmd)
|
dc_command_async(struct decoder_control *dc, enum decoder_command cmd)
|
||||||
{
|
{
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
|
|
||||||
dc->command = cmd;
|
dc->command = cmd;
|
||||||
decoder_signal(dc);
|
dc->Signal();
|
||||||
|
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
decoder_is_current_song(const struct decoder_control *dc,
|
decoder_control::IsCurrentSong(const struct song *_song) const
|
||||||
const struct song *song)
|
|
||||||
{
|
{
|
||||||
assert(dc != NULL);
|
assert(_song != NULL);
|
||||||
assert(song != NULL);
|
|
||||||
|
|
||||||
switch (dc->state) {
|
switch (state) {
|
||||||
case DECODE_STATE_STOP:
|
case DECODE_STATE_STOP:
|
||||||
case DECODE_STATE_ERROR:
|
case DECODE_STATE_ERROR:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case DECODE_STATE_START:
|
case DECODE_STATE_START:
|
||||||
case DECODE_STATE_DECODE:
|
case DECODE_STATE_DECODE:
|
||||||
return song_equals(dc->song, song);
|
return song_equals(song, _song);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
@ -126,99 +108,91 @@ decoder_is_current_song(const struct decoder_control *dc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
dc_start(struct decoder_control *dc, struct song *song,
|
decoder_control::Start(struct song *_song,
|
||||||
unsigned start_ms, unsigned end_ms,
|
unsigned _start_ms, unsigned _end_ms,
|
||||||
struct music_buffer *buffer, struct music_pipe *pipe)
|
music_buffer *_buffer, music_pipe *_pipe)
|
||||||
{
|
{
|
||||||
assert(song != NULL);
|
assert(_song != NULL);
|
||||||
assert(buffer != NULL);
|
assert(buffer != NULL);
|
||||||
assert(pipe != NULL);
|
assert(pipe != NULL);
|
||||||
assert(music_pipe_empty(pipe));
|
assert(music_pipe_empty(pipe));
|
||||||
|
|
||||||
if (dc->song != NULL)
|
if (song != nullptr)
|
||||||
song_free(dc->song);
|
song_free(song);
|
||||||
|
|
||||||
dc->song = song;
|
song = _song;
|
||||||
dc->start_ms = start_ms;
|
start_ms = _start_ms;
|
||||||
dc->end_ms = end_ms;
|
end_ms = _end_ms;
|
||||||
dc->buffer = buffer;
|
buffer = _buffer;
|
||||||
dc->pipe = pipe;
|
pipe = _pipe;
|
||||||
dc_command(dc, DECODE_COMMAND_START);
|
|
||||||
|
dc_command(this, DECODE_COMMAND_START);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
dc_stop(struct decoder_control *dc)
|
decoder_control::Stop()
|
||||||
{
|
{
|
||||||
decoder_lock(dc);
|
Lock();
|
||||||
|
|
||||||
if (dc->command != DECODE_COMMAND_NONE)
|
if (command != DECODE_COMMAND_NONE)
|
||||||
/* Attempt to cancel the current command. If it's too
|
/* Attempt to cancel the current command. If it's too
|
||||||
late and the decoder thread is already executing
|
late and the decoder thread is already executing
|
||||||
the old command, we'll call STOP again in this
|
the old command, we'll call STOP again in this
|
||||||
function (see below). */
|
function (see below). */
|
||||||
dc_command_locked(dc, DECODE_COMMAND_STOP);
|
dc_command_locked(this, DECODE_COMMAND_STOP);
|
||||||
|
|
||||||
if (dc->state != DECODE_STATE_STOP && dc->state != DECODE_STATE_ERROR)
|
if (state != DECODE_STATE_STOP && state != DECODE_STATE_ERROR)
|
||||||
dc_command_locked(dc, DECODE_COMMAND_STOP);
|
dc_command_locked(this, DECODE_COMMAND_STOP);
|
||||||
|
|
||||||
decoder_unlock(dc);
|
Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
dc_seek(struct decoder_control *dc, double where)
|
decoder_control::Seek(double where)
|
||||||
{
|
{
|
||||||
assert(dc->state != DECODE_STATE_START);
|
assert(state != DECODE_STATE_START);
|
||||||
assert(where >= 0.0);
|
assert(where >= 0.0);
|
||||||
|
|
||||||
if (dc->state == DECODE_STATE_STOP ||
|
if (state == DECODE_STATE_STOP ||
|
||||||
dc->state == DECODE_STATE_ERROR || !dc->seekable)
|
state == DECODE_STATE_ERROR || !seekable)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
dc->seek_where = where;
|
seek_where = where;
|
||||||
dc->seek_error = false;
|
seek_error = false;
|
||||||
dc_command(dc, DECODE_COMMAND_SEEK);
|
dc_command(this, DECODE_COMMAND_SEEK);
|
||||||
|
|
||||||
if (dc->seek_error)
|
return !seek_error;
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
dc_quit(struct decoder_control *dc)
|
decoder_control::Quit()
|
||||||
{
|
{
|
||||||
assert(dc->thread != NULL);
|
assert(thread != nullptr);
|
||||||
|
|
||||||
dc->quit = true;
|
quit = true;
|
||||||
dc_command_async(dc, DECODE_COMMAND_STOP);
|
dc_command_async(this, DECODE_COMMAND_STOP);
|
||||||
|
|
||||||
g_thread_join(dc->thread);
|
g_thread_join(thread);
|
||||||
dc->thread = NULL;
|
thread = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
dc_mixramp_start(struct decoder_control *dc, char *mixramp_start)
|
decoder_control::MixRampStart(char *_mixramp_start)
|
||||||
{
|
{
|
||||||
assert(dc != NULL);
|
g_free(mixramp_start);
|
||||||
|
mixramp_start = _mixramp_start;
|
||||||
g_free(dc->mixramp_start);
|
|
||||||
dc->mixramp_start = mixramp_start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
dc_mixramp_end(struct decoder_control *dc, char *mixramp_end)
|
decoder_control::MixRampEnd(char *_mixramp_end)
|
||||||
{
|
{
|
||||||
assert(dc != NULL);
|
g_free(mixramp_end);
|
||||||
|
mixramp_end = _mixramp_end;
|
||||||
g_free(dc->mixramp_end);
|
|
||||||
dc->mixramp_end = mixramp_end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
dc_mixramp_prev_end(struct decoder_control *dc, char *mixramp_prev_end)
|
decoder_control::MixRampPrevEnd(char *_mixramp_prev_end)
|
||||||
{
|
{
|
||||||
assert(dc != NULL);
|
g_free(mixramp_prev_end);
|
||||||
|
mixramp_prev_end = _mixramp_prev_end;
|
||||||
g_free(dc->mixramp_prev_end);
|
|
||||||
dc->mixramp_prev_end = mixramp_prev_end;
|
|
||||||
}
|
}
|
||||||
|
@ -130,6 +130,41 @@ struct decoder_control {
|
|||||||
char *mixramp_end;
|
char *mixramp_end;
|
||||||
char *mixramp_prev_end;
|
char *mixramp_prev_end;
|
||||||
|
|
||||||
|
decoder_control();
|
||||||
|
~decoder_control();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks the object.
|
||||||
|
*/
|
||||||
|
void Lock() const {
|
||||||
|
g_mutex_lock(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlocks the object.
|
||||||
|
*/
|
||||||
|
void Unlock() const {
|
||||||
|
g_mutex_unlock(mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals the object. This function is only valid in the
|
||||||
|
* player thread. The object should be locked prior to
|
||||||
|
* calling this function.
|
||||||
|
*/
|
||||||
|
void Signal() {
|
||||||
|
g_cond_signal(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for a signal on the #decoder_control object. This function
|
||||||
|
* is only valid in the decoder thread. The object must be locked
|
||||||
|
* prior to calling this function.
|
||||||
|
*/
|
||||||
|
void Wait() {
|
||||||
|
g_cond_wait(cond, mutex);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for a signal from the decoder thread. This object
|
* Waits for a signal from the decoder thread. This object
|
||||||
* must be locked prior to calling this function. This method
|
* must be locked prior to calling this function. This method
|
||||||
@ -138,211 +173,123 @@ struct decoder_control {
|
|||||||
void WaitForDecoder() {
|
void WaitForDecoder() {
|
||||||
g_cond_wait(client_cond, mutex);
|
g_cond_wait(client_cond, mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsIdle() const {
|
||||||
|
return state == DECODE_STATE_STOP ||
|
||||||
|
state == DECODE_STATE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
gcc_pure
|
||||||
|
bool LockIsIdle() const {
|
||||||
|
Lock();
|
||||||
|
bool result = IsIdle();
|
||||||
|
Unlock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsStarting() const {
|
||||||
|
return state == DECODE_STATE_START;
|
||||||
|
}
|
||||||
|
|
||||||
|
gcc_pure
|
||||||
|
bool LockIsStarting() const {
|
||||||
|
Lock();
|
||||||
|
bool result = IsStarting();
|
||||||
|
Unlock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasFailed() const {
|
||||||
|
assert(command == DECODE_COMMAND_NONE);
|
||||||
|
|
||||||
|
return state == DECODE_STATE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
gcc_pure
|
||||||
|
bool LockHasFailed() const {
|
||||||
|
Lock();
|
||||||
|
bool result = HasFailed();
|
||||||
|
Unlock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether an error has occurred, and if so, returns a newly
|
||||||
|
* allocated copy of the #GError object.
|
||||||
|
*
|
||||||
|
* Caller must lock the object.
|
||||||
|
*/
|
||||||
|
GError *GetError() const {
|
||||||
|
assert(command == DECODE_COMMAND_NONE);
|
||||||
|
assert(state != DECODE_STATE_ERROR || error != nullptr);
|
||||||
|
|
||||||
|
return state == DECODE_STATE_ERROR
|
||||||
|
? g_error_copy(error)
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like dc_get_error(), but locks and unlocks the object.
|
||||||
|
*/
|
||||||
|
GError *LockGetError() const {
|
||||||
|
Lock();
|
||||||
|
GError *result = GetError();
|
||||||
|
Unlock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the error condition and free the #GError object (if any).
|
||||||
|
*
|
||||||
|
* Caller must lock the object.
|
||||||
|
*/
|
||||||
|
void ClearError() {
|
||||||
|
if (state == DECODE_STATE_ERROR) {
|
||||||
|
g_error_free(error);
|
||||||
|
state = DECODE_STATE_STOP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the specified song is currently being decoded. If the
|
||||||
|
* decoder is not running currently (or being started), then this
|
||||||
|
* function returns false in any case.
|
||||||
|
*
|
||||||
|
* Caller must lock the object.
|
||||||
|
*/
|
||||||
|
gcc_pure
|
||||||
|
bool IsCurrentSong(const struct song *_song) const;
|
||||||
|
|
||||||
|
gcc_pure
|
||||||
|
bool LockIsCurrentSong(const struct song *_song) const {
|
||||||
|
Lock();
|
||||||
|
const bool result = IsCurrentSong(_song);
|
||||||
|
Unlock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the decoder.
|
||||||
|
*
|
||||||
|
* @param song the song to be decoded; the given instance will be
|
||||||
|
* owned and freed by the decoder
|
||||||
|
* @param start_ms see #decoder_control
|
||||||
|
* @param end_ms see #decoder_control
|
||||||
|
* @param pipe the pipe which receives the decoded chunks (owned by
|
||||||
|
* the caller)
|
||||||
|
*/
|
||||||
|
void Start(struct song *song, unsigned start_ms, unsigned end_ms,
|
||||||
|
music_buffer *buffer, music_pipe *pipe);
|
||||||
|
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
bool Seek(double where);
|
||||||
|
|
||||||
|
void Quit();
|
||||||
|
|
||||||
|
void MixRampStart(char *_mixramp_start);
|
||||||
|
void MixRampEnd(char *_mixramp_end);
|
||||||
|
void MixRampPrevEnd(char *_mixramp_prev_end);
|
||||||
};
|
};
|
||||||
|
|
||||||
G_GNUC_MALLOC
|
|
||||||
struct decoder_control *
|
|
||||||
dc_new();
|
|
||||||
|
|
||||||
void
|
|
||||||
dc_free(struct decoder_control *dc);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locks the #decoder_control object.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
decoder_lock(struct decoder_control *dc)
|
|
||||||
{
|
|
||||||
g_mutex_lock(dc->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unlocks the #decoder_control object.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
decoder_unlock(struct decoder_control *dc)
|
|
||||||
{
|
|
||||||
g_mutex_unlock(dc->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Waits for a signal on the #decoder_control object. This function
|
|
||||||
* is only valid in the decoder thread. The object must be locked
|
|
||||||
* prior to calling this function.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
decoder_wait(struct decoder_control *dc)
|
|
||||||
{
|
|
||||||
g_cond_wait(dc->cond, dc->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals the #decoder_control object. This function is only valid
|
|
||||||
* in the player thread. The object should be locked prior to calling
|
|
||||||
* this function.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
decoder_signal(struct decoder_control *dc)
|
|
||||||
{
|
|
||||||
g_cond_signal(dc->cond);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
decoder_is_idle(const struct decoder_control *dc)
|
|
||||||
{
|
|
||||||
return dc->state == DECODE_STATE_STOP ||
|
|
||||||
dc->state == DECODE_STATE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
decoder_is_starting(const struct decoder_control *dc)
|
|
||||||
{
|
|
||||||
return dc->state == DECODE_STATE_START;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
decoder_has_failed(const struct decoder_control *dc)
|
|
||||||
{
|
|
||||||
assert(dc->command == DECODE_COMMAND_NONE);
|
|
||||||
|
|
||||||
return dc->state == DECODE_STATE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether an error has occurred, and if so, returns a newly
|
|
||||||
* allocated copy of the #GError object.
|
|
||||||
*
|
|
||||||
* Caller must lock the object.
|
|
||||||
*/
|
|
||||||
static inline GError *
|
|
||||||
dc_get_error(const struct decoder_control *dc)
|
|
||||||
{
|
|
||||||
assert(dc != NULL);
|
|
||||||
assert(dc->command == DECODE_COMMAND_NONE);
|
|
||||||
assert(dc->state != DECODE_STATE_ERROR || dc->error != NULL);
|
|
||||||
|
|
||||||
return dc->state == DECODE_STATE_ERROR
|
|
||||||
? g_error_copy(dc->error)
|
|
||||||
: NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Like dc_get_error(), but locks and unlocks the object.
|
|
||||||
*/
|
|
||||||
static inline GError *
|
|
||||||
dc_lock_get_error(struct decoder_control *dc)
|
|
||||||
{
|
|
||||||
decoder_lock(dc);
|
|
||||||
GError *error = dc_get_error(dc);
|
|
||||||
decoder_unlock(dc);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear the error condition and free the #GError object (if any).
|
|
||||||
*
|
|
||||||
* Caller must lock the object.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
dc_clear_error(struct decoder_control *dc)
|
|
||||||
{
|
|
||||||
if (dc->state == DECODE_STATE_ERROR) {
|
|
||||||
g_error_free(dc->error);
|
|
||||||
dc->state = DECODE_STATE_STOP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
decoder_lock_is_idle(struct decoder_control *dc)
|
|
||||||
{
|
|
||||||
bool ret;
|
|
||||||
|
|
||||||
decoder_lock(dc);
|
|
||||||
ret = decoder_is_idle(dc);
|
|
||||||
decoder_unlock(dc);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
decoder_lock_is_starting(struct decoder_control *dc)
|
|
||||||
{
|
|
||||||
bool ret;
|
|
||||||
|
|
||||||
decoder_lock(dc);
|
|
||||||
ret = decoder_is_starting(dc);
|
|
||||||
decoder_unlock(dc);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
decoder_lock_has_failed(struct decoder_control *dc)
|
|
||||||
{
|
|
||||||
bool ret;
|
|
||||||
|
|
||||||
decoder_lock(dc);
|
|
||||||
ret = decoder_has_failed(dc);
|
|
||||||
decoder_unlock(dc);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the specified song is currently being decoded. If the
|
|
||||||
* decoder is not running currently (or being started), then this
|
|
||||||
* function returns false in any case.
|
|
||||||
*
|
|
||||||
* Caller must lock the object.
|
|
||||||
*/
|
|
||||||
gcc_pure
|
|
||||||
bool
|
|
||||||
decoder_is_current_song(const struct decoder_control *dc,
|
|
||||||
const struct song *song);
|
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
static inline bool
|
|
||||||
decoder_lock_is_current_song(struct decoder_control *dc,
|
|
||||||
const struct song *song)
|
|
||||||
{
|
|
||||||
decoder_lock(dc);
|
|
||||||
const bool result = decoder_is_current_song(dc, song);
|
|
||||||
decoder_unlock(dc);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the decoder.
|
|
||||||
*
|
|
||||||
* @param the decoder
|
|
||||||
* @param song the song to be decoded; the given instance will be
|
|
||||||
* owned and freed by the decoder
|
|
||||||
* @param start_ms see #decoder_control
|
|
||||||
* @param end_ms see #decoder_control
|
|
||||||
* @param pipe the pipe which receives the decoded chunks (owned by
|
|
||||||
* the caller)
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
dc_start(struct decoder_control *dc, struct song *song,
|
|
||||||
unsigned start_ms, unsigned end_ms,
|
|
||||||
struct music_buffer *buffer, struct music_pipe *pipe);
|
|
||||||
|
|
||||||
void
|
|
||||||
dc_stop(struct decoder_control *dc);
|
|
||||||
|
|
||||||
bool
|
|
||||||
dc_seek(struct decoder_control *dc, double where);
|
|
||||||
|
|
||||||
void
|
|
||||||
dc_quit(struct decoder_control *dc);
|
|
||||||
|
|
||||||
void
|
|
||||||
dc_mixramp_start(struct decoder_control *dc, char *mixramp_start);
|
|
||||||
|
|
||||||
void
|
|
||||||
dc_mixramp_end(struct decoder_control *dc, char *mixramp_end);
|
|
||||||
|
|
||||||
void
|
|
||||||
dc_mixramp_prev_end(struct decoder_control *dc, char *mixramp_prev_end);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -57,7 +57,7 @@ need_chunks(struct decoder_control *dc, bool do_wait)
|
|||||||
return dc->command;
|
return dc->command;
|
||||||
|
|
||||||
if (do_wait) {
|
if (do_wait) {
|
||||||
decoder_wait(dc);
|
dc->Wait();
|
||||||
g_cond_signal(dc->client_cond);
|
g_cond_signal(dc->client_cond);
|
||||||
|
|
||||||
return dc->command;
|
return dc->command;
|
||||||
@ -89,9 +89,9 @@ decoder_get_chunk(struct decoder *decoder)
|
|||||||
return decoder->chunk;
|
return decoder->chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
cmd = need_chunks(dc, true);
|
cmd = need_chunks(dc, true);
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
} while (cmd == DECODE_COMMAND_NONE);
|
} while (cmd == DECODE_COMMAND_NONE);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -91,18 +91,18 @@ decoder_input_stream_open(struct decoder_control *dc, const char *uri)
|
|||||||
/* wait for the input stream to become ready; its metadata
|
/* wait for the input stream to become ready; its metadata
|
||||||
will be available then */
|
will be available then */
|
||||||
|
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
|
|
||||||
input_stream_update(is);
|
input_stream_update(is);
|
||||||
while (!is->ready &&
|
while (!is->ready &&
|
||||||
dc->command != DECODE_COMMAND_STOP) {
|
dc->command != DECODE_COMMAND_STOP) {
|
||||||
decoder_wait(dc);
|
dc->Wait();
|
||||||
|
|
||||||
input_stream_update(is);
|
input_stream_update(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!input_stream_check(is, &error)) {
|
if (!input_stream_check(is, &error)) {
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
g_warning("%s", error->message);
|
g_warning("%s", error->message);
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
@ -110,7 +110,7 @@ decoder_input_stream_open(struct decoder_control *dc, const char *uri)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
@ -137,11 +137,11 @@ decoder_stream_decode(const struct decoder_plugin *plugin,
|
|||||||
/* rewind the stream, so each plugin gets a fresh start */
|
/* rewind the stream, so each plugin gets a fresh start */
|
||||||
input_stream_seek(input_stream, 0, SEEK_SET, NULL);
|
input_stream_seek(input_stream, 0, SEEK_SET, NULL);
|
||||||
|
|
||||||
decoder_unlock(decoder->dc);
|
decoder->dc->Unlock();
|
||||||
|
|
||||||
decoder_plugin_stream_decode(plugin, decoder, input_stream);
|
decoder_plugin_stream_decode(plugin, decoder, input_stream);
|
||||||
|
|
||||||
decoder_lock(decoder->dc);
|
decoder->dc->Lock();
|
||||||
|
|
||||||
assert(decoder->dc->state == DECODE_STATE_START ||
|
assert(decoder->dc->state == DECODE_STATE_START ||
|
||||||
decoder->dc->state == DECODE_STATE_DECODE);
|
decoder->dc->state == DECODE_STATE_DECODE);
|
||||||
@ -167,11 +167,11 @@ decoder_file_decode(const struct decoder_plugin *plugin,
|
|||||||
if (decoder->dc->command == DECODE_COMMAND_STOP)
|
if (decoder->dc->command == DECODE_COMMAND_STOP)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
decoder_unlock(decoder->dc);
|
decoder->dc->Unlock();
|
||||||
|
|
||||||
decoder_plugin_file_decode(plugin, decoder, path);
|
decoder_plugin_file_decode(plugin, decoder, path);
|
||||||
|
|
||||||
decoder_lock(decoder->dc);
|
decoder->dc->Lock();
|
||||||
|
|
||||||
assert(decoder->dc->state == DECODE_STATE_START ||
|
assert(decoder->dc->state == DECODE_STATE_START ||
|
||||||
decoder->dc->state == DECODE_STATE_DECODE);
|
decoder->dc->state == DECODE_STATE_DECODE);
|
||||||
@ -280,15 +280,15 @@ decoder_run_stream(struct decoder *decoder, const char *uri)
|
|||||||
struct input_stream *input_stream;
|
struct input_stream *input_stream;
|
||||||
bool success;
|
bool success;
|
||||||
|
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
input_stream = decoder_input_stream_open(dc, uri);
|
input_stream = decoder_input_stream_open(dc, uri);
|
||||||
if (input_stream == NULL) {
|
if (input_stream == NULL) {
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
|
|
||||||
GSList *tried = NULL;
|
GSList *tried = NULL;
|
||||||
|
|
||||||
@ -305,9 +305,9 @@ decoder_run_stream(struct decoder *decoder, const char *uri)
|
|||||||
|
|
||||||
g_slist_free(tried);
|
g_slist_free(tried);
|
||||||
|
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
input_stream_close(input_stream);
|
input_stream_close(input_stream);
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
@ -337,18 +337,18 @@ decoder_run_file(struct decoder *decoder, const char *path_fs)
|
|||||||
if (suffix == NULL)
|
if (suffix == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
decoder_load_replay_gain(decoder, path_fs);
|
decoder_load_replay_gain(decoder, path_fs);
|
||||||
|
|
||||||
while ((plugin = decoder_plugin_from_suffix(suffix, plugin)) != NULL) {
|
while ((plugin = decoder_plugin_from_suffix(suffix, plugin)) != NULL) {
|
||||||
if (plugin->file_decode != NULL) {
|
if (plugin->file_decode != NULL) {
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
|
|
||||||
if (decoder_file_decode(plugin, decoder, path_fs))
|
if (decoder_file_decode(plugin, decoder, path_fs))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
} else if (plugin->stream_decode != NULL) {
|
} else if (plugin->stream_decode != NULL) {
|
||||||
struct input_stream *input_stream;
|
struct input_stream *input_stream;
|
||||||
bool success;
|
bool success;
|
||||||
@ -357,23 +357,23 @@ decoder_run_file(struct decoder *decoder, const char *path_fs)
|
|||||||
if (input_stream == NULL)
|
if (input_stream == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
|
|
||||||
success = decoder_stream_decode(plugin, decoder,
|
success = decoder_stream_decode(plugin, decoder,
|
||||||
input_stream);
|
input_stream);
|
||||||
|
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
input_stream_close(input_stream);
|
input_stream_close(input_stream);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,14 +394,14 @@ decoder_run_song(struct decoder_control *dc,
|
|||||||
? decoder_run_file(&decoder, uri)
|
? decoder_run_file(&decoder, uri)
|
||||||
: decoder_run_stream(&decoder, uri);
|
: decoder_run_stream(&decoder, uri);
|
||||||
|
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
/* flush the last chunk */
|
/* flush the last chunk */
|
||||||
|
|
||||||
if (decoder.chunk != NULL)
|
if (decoder.chunk != NULL)
|
||||||
decoder_flush_chunk(&decoder);
|
decoder_flush_chunk(&decoder);
|
||||||
|
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
@ -424,7 +424,7 @@ decoder_run_song(struct decoder_control *dc,
|
|||||||
static void
|
static void
|
||||||
decoder_run(struct decoder_control *dc)
|
decoder_run(struct decoder_control *dc)
|
||||||
{
|
{
|
||||||
dc_clear_error(dc);
|
dc->ClearError();
|
||||||
|
|
||||||
const struct song *song = dc->song;
|
const struct song *song = dc->song;
|
||||||
char *uri;
|
char *uri;
|
||||||
@ -455,7 +455,7 @@ decoder_task(gpointer arg)
|
|||||||
{
|
{
|
||||||
struct decoder_control *dc = (struct decoder_control *)arg;
|
struct decoder_control *dc = (struct decoder_control *)arg;
|
||||||
|
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
assert(dc->state == DECODE_STATE_STOP ||
|
assert(dc->state == DECODE_STATE_STOP ||
|
||||||
@ -463,8 +463,8 @@ decoder_task(gpointer arg)
|
|||||||
|
|
||||||
switch (dc->command) {
|
switch (dc->command) {
|
||||||
case DECODE_COMMAND_START:
|
case DECODE_COMMAND_START:
|
||||||
dc_mixramp_start(dc, NULL);
|
dc->MixRampStart(nullptr);
|
||||||
dc_mixramp_prev_end(dc, dc->mixramp_end);
|
dc->MixRampPrevEnd(dc->mixramp_end);
|
||||||
dc->mixramp_end = NULL; /* Don't free, it's copied above. */
|
dc->mixramp_end = NULL; /* Don't free, it's copied above. */
|
||||||
dc->replay_gain_prev_db = dc->replay_gain_db;
|
dc->replay_gain_prev_db = dc->replay_gain_db;
|
||||||
dc->replay_gain_db = 0;
|
dc->replay_gain_db = 0;
|
||||||
@ -480,12 +480,12 @@ decoder_task(gpointer arg)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DECODE_COMMAND_NONE:
|
case DECODE_COMMAND_NONE:
|
||||||
decoder_wait(dc);
|
dc->Wait();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (dc->command != DECODE_COMMAND_NONE || !dc->quit);
|
} while (dc->command != DECODE_COMMAND_NONE || !dc->quit);
|
||||||
|
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -176,9 +176,9 @@ player_dc_start(struct player *player, struct music_pipe *pipe)
|
|||||||
if (pc->command == PLAYER_COMMAND_SEEK)
|
if (pc->command == PLAYER_COMMAND_SEEK)
|
||||||
start_ms += (unsigned)(pc->seek_where * 1000);
|
start_ms += (unsigned)(pc->seek_where * 1000);
|
||||||
|
|
||||||
dc_start(dc, song_dup_detached(pc->next_song),
|
dc->Start(song_dup_detached(pc->next_song),
|
||||||
start_ms, pc->next_song->end_ms,
|
start_ms, pc->next_song->end_ms,
|
||||||
player_buffer, pipe);
|
player_buffer, pipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -217,7 +217,7 @@ player_dc_stop(struct player *player)
|
|||||||
{
|
{
|
||||||
struct decoder_control *dc = player->dc;
|
struct decoder_control *dc = player->dc;
|
||||||
|
|
||||||
dc_stop(dc);
|
dc->Stop();
|
||||||
|
|
||||||
if (dc->pipe != NULL) {
|
if (dc->pipe != NULL) {
|
||||||
/* clear and free the decoder pipe */
|
/* clear and free the decoder pipe */
|
||||||
@ -249,7 +249,7 @@ player_wait_for_decoder(struct player *player)
|
|||||||
|
|
||||||
player->queued = false;
|
player->queued = false;
|
||||||
|
|
||||||
GError *error = dc_lock_get_error(dc);
|
GError *error = dc->LockGetError();
|
||||||
if (error != NULL) {
|
if (error != NULL) {
|
||||||
pc->Lock();
|
pc->Lock();
|
||||||
pc->SetError(PLAYER_ERROR_DECODER, error);
|
pc->SetError(PLAYER_ERROR_DECODER, error);
|
||||||
@ -369,22 +369,22 @@ player_check_decoder_startup(struct player *player)
|
|||||||
|
|
||||||
assert(player->decoder_starting);
|
assert(player->decoder_starting);
|
||||||
|
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
|
|
||||||
GError *error = dc_get_error(dc);
|
GError *error = dc->GetError();
|
||||||
if (error != NULL) {
|
if (error != NULL) {
|
||||||
/* the decoder failed */
|
/* the decoder failed */
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
pc->Lock();
|
pc->Lock();
|
||||||
pc->SetError(PLAYER_ERROR_DECODER, error);
|
pc->SetError(PLAYER_ERROR_DECODER, error);
|
||||||
pc->Unlock();
|
pc->Unlock();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else if (!decoder_is_starting(dc)) {
|
} else if (!dc->IsStarting()) {
|
||||||
/* the decoder is ready and ok */
|
/* the decoder is ready and ok */
|
||||||
|
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
if (player->output_open &&
|
if (player->output_open &&
|
||||||
!audio_output_all_wait(pc, 1))
|
!audio_output_all_wait(pc, 1))
|
||||||
@ -414,7 +414,7 @@ player_check_decoder_startup(struct player *player)
|
|||||||
/* the decoder is not yet ready; wait
|
/* the decoder is not yet ready; wait
|
||||||
some more */
|
some more */
|
||||||
dc->WaitForDecoder();
|
dc->WaitForDecoder();
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -480,7 +480,7 @@ static bool player_seek_decoder(struct player *player)
|
|||||||
|
|
||||||
const unsigned start_ms = song->start_ms;
|
const unsigned start_ms = song->start_ms;
|
||||||
|
|
||||||
if (!decoder_lock_is_current_song(dc, song)) {
|
if (!dc->LockIsCurrentSong(song)) {
|
||||||
/* the decoder is already decoding the "next" song -
|
/* the decoder is already decoding the "next" song -
|
||||||
stop it and start the previous song again */
|
stop it and start the previous song again */
|
||||||
|
|
||||||
@ -529,7 +529,7 @@ static bool player_seek_decoder(struct player *player)
|
|||||||
if (where < 0.0)
|
if (where < 0.0)
|
||||||
where = 0.0;
|
where = 0.0;
|
||||||
|
|
||||||
if (!dc_seek(dc, where + start_ms / 1000.0)) {
|
if (!dc->Seek(where + start_ms / 1000.0)) {
|
||||||
/* decoder failure */
|
/* decoder failure */
|
||||||
player_command_finished(pc);
|
player_command_finished(pc);
|
||||||
return false;
|
return false;
|
||||||
@ -782,19 +782,19 @@ play_next_chunk(struct player *player)
|
|||||||
} else {
|
} else {
|
||||||
/* there are not enough decoded chunks yet */
|
/* there are not enough decoded chunks yet */
|
||||||
|
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
|
|
||||||
if (decoder_is_idle(dc)) {
|
if (dc->IsIdle()) {
|
||||||
/* the decoder isn't running, abort
|
/* the decoder isn't running, abort
|
||||||
cross fading */
|
cross fading */
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
player->xfade = XFADE_DISABLED;
|
player->xfade = XFADE_DISABLED;
|
||||||
} else {
|
} else {
|
||||||
/* wait for the decoder */
|
/* wait for the decoder */
|
||||||
decoder_signal(dc);
|
dc->Signal();
|
||||||
dc->WaitForDecoder();
|
dc->WaitForDecoder();
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -840,12 +840,12 @@ play_next_chunk(struct player *player)
|
|||||||
/* this formula should prevent that the decoder gets woken up
|
/* this formula should prevent that the decoder gets woken up
|
||||||
with each chunk; it is more efficient to make it decode a
|
with each chunk; it is more efficient to make it decode a
|
||||||
larger block at a time */
|
larger block at a time */
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
if (!decoder_is_idle(dc) &&
|
if (!dc->IsIdle() &&
|
||||||
music_pipe_size(dc->pipe) <= (pc->buffered_before_play +
|
music_pipe_size(dc->pipe) <= (pc->buffered_before_play +
|
||||||
music_buffer_size(player_buffer) * 3) / 4)
|
music_buffer_size(player_buffer) * 3) / 4)
|
||||||
decoder_signal(dc);
|
dc->Signal();
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -940,7 +940,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
|
|||||||
prevent stuttering on slow machines */
|
prevent stuttering on slow machines */
|
||||||
|
|
||||||
if (music_pipe_size(player.pipe) < pc->buffered_before_play &&
|
if (music_pipe_size(player.pipe) < pc->buffered_before_play &&
|
||||||
!decoder_lock_is_idle(dc)) {
|
!dc->LockIsIdle()) {
|
||||||
/* not enough decoded buffer space yet */
|
/* not enough decoded buffer space yet */
|
||||||
|
|
||||||
if (!player.paused &&
|
if (!player.paused &&
|
||||||
@ -949,10 +949,10 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
|
|||||||
!player_send_silence(&player))
|
!player_send_silence(&player))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
decoder_lock(dc);
|
dc->Lock();
|
||||||
/* XXX race condition: check decoder again */
|
/* XXX race condition: check decoder again */
|
||||||
dc->WaitForDecoder();
|
dc->WaitForDecoder();
|
||||||
decoder_unlock(dc);
|
dc->Unlock();
|
||||||
pc->Lock();
|
pc->Lock();
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
@ -979,7 +979,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
|
|||||||
*/
|
*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (decoder_lock_is_idle(dc) && player.queued &&
|
if (dc->LockIsIdle() && player.queued &&
|
||||||
dc->pipe == player.pipe) {
|
dc->pipe == player.pipe) {
|
||||||
/* the decoder has finished the current song;
|
/* the decoder has finished the current song;
|
||||||
make it decode the next song */
|
make it decode the next song */
|
||||||
@ -994,7 +994,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
|
|||||||
!pc->border_pause &&
|
!pc->border_pause &&
|
||||||
player_dc_at_next_song(&player) &&
|
player_dc_at_next_song(&player) &&
|
||||||
player.xfade == XFADE_UNKNOWN &&
|
player.xfade == XFADE_UNKNOWN &&
|
||||||
!decoder_lock_is_starting(dc)) {
|
!dc->LockIsStarting()) {
|
||||||
/* enable cross fading in this song? if yes,
|
/* enable cross fading in this song? if yes,
|
||||||
calculate how many chunks will be required
|
calculate how many chunks will be required
|
||||||
for it */
|
for it */
|
||||||
@ -1042,7 +1042,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
|
|||||||
|
|
||||||
if (!player_song_border(&player))
|
if (!player_song_border(&player))
|
||||||
break;
|
break;
|
||||||
} else if (decoder_lock_is_idle(dc)) {
|
} else if (dc->LockIsIdle()) {
|
||||||
/* 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 */
|
||||||
@ -1096,7 +1096,7 @@ player_task(gpointer arg)
|
|||||||
{
|
{
|
||||||
struct player_control *pc = (struct player_control *)arg;
|
struct player_control *pc = (struct player_control *)arg;
|
||||||
|
|
||||||
struct decoder_control *dc = dc_new();
|
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 = music_buffer_new(pc->buffer_chunks);
|
||||||
@ -1156,8 +1156,8 @@ player_task(gpointer arg)
|
|||||||
case PLAYER_COMMAND_EXIT:
|
case PLAYER_COMMAND_EXIT:
|
||||||
pc->Unlock();
|
pc->Unlock();
|
||||||
|
|
||||||
dc_quit(dc);
|
dc->Quit();
|
||||||
dc_free(dc);
|
delete dc;
|
||||||
audio_output_all_close();
|
audio_output_all_close();
|
||||||
music_buffer_free(player_buffer);
|
music_buffer_free(player_buffer);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user