aboutsummaryrefslogtreecommitdiffstats
path: root/src/PlayerThread.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/PlayerThread.cxx (renamed from src/player_thread.c)150
1 files changed, 92 insertions, 58 deletions
diff --git a/src/player_thread.c b/src/PlayerThread.cxx
index 707fb27ae..fb7432368 100644
--- a/src/player_thread.c
+++ b/src/PlayerThread.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * 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
@@ -18,23 +18,23 @@
*/
#include "config.h"
-#include "player_thread.h"
-#include "player_control.h"
-#include "decoder_control.h"
-#include "decoder_thread.h"
-#include "output_all.h"
-#include "pcm_volume.h"
-#include "path.h"
-#include "event_pipe.h"
-#include "crossfade.h"
+#include "PlayerThread.hxx"
+#include "DecoderThread.hxx"
+#include "DecoderControl.hxx"
+#include "MusicPipe.hxx"
+#include "MusicBuffer.hxx"
+#include "MusicChunk.hxx"
#include "song.h"
-#include "tag.h"
-#include "pipe.h"
-#include "chunk.h"
-#include "idle.h"
-#include "main.h"
-#include "buffer.h"
+#include "Main.hxx"
#include "mpd_error.h"
+#include "CrossFade.hxx"
+#include "PlayerControl.hxx"
+#include "OutputAll.hxx"
+#include "tag.h"
+#include "Idle.hxx"
+#include "GlobalEvents.hxx"
+
+#include <cmath>
#include <glib.h>
@@ -123,6 +123,20 @@ struct player {
* precisely.
*/
float elapsed_time;
+
+ player(player_control *_pc, decoder_control *_dc)
+ :pc(_pc), dc(_dc),
+ buffering(false),
+ decoder_starting(false),
+ paused(false),
+ queued(true),
+ output_open(false),
+ song(NULL),
+ xfade(XFADE_UNKNOWN),
+ cross_fading(false),
+ cross_fade_chunks(0),
+ cross_fade_tag(NULL),
+ elapsed_time(0.0) {}
};
static struct music_buffer *player_buffer;
@@ -133,7 +147,7 @@ player_command_finished_locked(struct player_control *pc)
assert(pc->command != PLAYER_COMMAND_NONE);
pc->command = PLAYER_COMMAND_NONE;
- g_cond_signal(main_cond);
+ pc->cond.signal();
}
static void
@@ -162,7 +176,7 @@ player_dc_start(struct player *player, struct music_pipe *pipe)
if (pc->command == PLAYER_COMMAND_SEEK)
start_ms += (unsigned)(pc->seek_where * 1000);
- dc_start(dc, pc->next_song,
+ dc_start(dc, song_dup_detached(pc->next_song),
start_ms, pc->next_song->end_ms,
player_buffer, pipe);
}
@@ -235,16 +249,22 @@ player_wait_for_decoder(struct player *player)
player->queued = false;
- if (decoder_lock_has_failed(dc)) {
+ GError *error = dc_lock_get_error(dc);
+ if (error != NULL) {
player_lock(pc);
- pc->errored_song = dc->song;
- pc->error = PLAYER_ERROR_FILE;
+ pc_set_error(pc, PLAYER_ERROR_DECODER, error);
+
+ song_free(pc->next_song);
pc->next_song = NULL;
+
player_unlock(pc);
return false;
}
+ if (player->song != NULL)
+ song_free(player->song);
+
player->song = pc->next_song;
player->elapsed_time = 0.0;
@@ -265,7 +285,7 @@ player_wait_for_decoder(struct player *player)
player_unlock(pc);
/* call syncPlaylistWithQueue() in the main thread */
- event_pipe_emit(PIPE_EVENT_PLAYLIST);
+ GlobalEvents::Emit(GlobalEvents::PLAYLIST);
return true;
}
@@ -305,7 +325,9 @@ player_open_output(struct player *player)
assert(pc->state == PLAYER_STATE_PLAY ||
pc->state == PLAYER_STATE_PAUSE);
- if (audio_output_all_open(&player->play_audio_format, player_buffer)) {
+ GError *error = NULL;
+ if (audio_output_all_open(&player->play_audio_format, player_buffer,
+ &error)) {
player->output_open = true;
player->paused = false;
@@ -315,6 +337,8 @@ player_open_output(struct player *player)
return true;
} else {
+ g_warning("%s", error->message);
+
player->output_open = false;
/* pause: the user may resume playback as soon as an
@@ -322,7 +346,7 @@ player_open_output(struct player *player)
player->paused = true;
player_lock(pc);
- pc->error = PLAYER_ERROR_AUDIO;
+ pc_set_error(pc, PLAYER_ERROR_OUTPUT, error);
pc->state = PLAYER_STATE_PAUSE;
player_unlock(pc);
@@ -347,13 +371,13 @@ player_check_decoder_startup(struct player *player)
decoder_lock(dc);
- if (decoder_has_failed(dc)) {
+ GError *error = dc_get_error(dc);
+ if (error != NULL) {
/* the decoder failed */
decoder_unlock(dc);
player_lock(pc);
- pc->errored_song = dc->song;
- pc->error = PLAYER_ERROR_FILE;
+ pc_set_error(pc, PLAYER_ERROR_DECODER, error);
player_unlock(pc);
return false;
@@ -429,7 +453,11 @@ player_send_silence(struct player *player)
chunk->length = num_frames * frame_size;
memset(chunk->data, 0, chunk->length);
- if (!audio_output_all_play(chunk)) {
+ GError *error = NULL;
+ if (!audio_output_all_play(chunk, &error)) {
+ g_warning("%s", error->message);
+ g_error_free(error);
+
music_buffer_return(player_buffer, chunk);
return false;
}
@@ -452,7 +480,7 @@ static bool player_seek_decoder(struct player *player)
const unsigned start_ms = song->start_ms;
- if (decoder_current_song(dc) != song) {
+ if (!decoder_lock_is_current_song(dc, song)) {
/* the decoder is already decoding the "next" song -
stop it and start the previous song again */
@@ -478,6 +506,7 @@ static bool player_seek_decoder(struct player *player)
player->pipe = dc->pipe;
}
+ song_free(pc->next_song);
pc->next_song = NULL;
player->queued = false;
}
@@ -598,6 +627,7 @@ static void player_process_command(struct player *player)
player_lock(pc);
}
+ song_free(pc->next_song);
pc->next_song = NULL;
player->queued = false;
player_command_finished_locked(pc);
@@ -635,7 +665,7 @@ update_song_tag(struct song *song, const struct tag *new_tag)
/* the main thread will update the playlist version when he
receives this event */
- event_pipe_emit(PIPE_EVENT_TAG);
+ GlobalEvents::Emit(GlobalEvents::TAG);
/* notify all clients that the tag of the current song has
changed */
@@ -652,9 +682,10 @@ update_song_tag(struct song *song, const struct tag *new_tag)
static bool
play_chunk(struct player_control *pc,
struct song *song, struct music_chunk *chunk,
- const struct audio_format *format)
+ const struct audio_format *format,
+ GError **error_r)
{
- assert(music_chunk_check_format(chunk, format));
+ assert(chunk->CheckFormat(*format));
if (chunk->tag != NULL)
update_song_tag(song, chunk->tag);
@@ -670,7 +701,7 @@ play_chunk(struct player_control *pc,
/* send the chunk to the audio outputs */
- if (!audio_output_all_play(chunk))
+ if (!audio_output_all_play(chunk, error_r))
return false;
pc->total_play_time += (double)chunk->length /
@@ -727,14 +758,14 @@ play_next_chunk(struct player *player)
other_chunk->tag);
other_chunk->tag = NULL;
- if (isnan(pc->mixramp_delay_seconds)) {
+ if (std::isnan(pc->mixramp_delay_seconds)) {
chunk->mix_ratio = ((float)cross_fade_position)
/ player->cross_fade_chunks;
} else {
chunk->mix_ratio = nan("");
}
- if (music_chunk_is_empty(other_chunk)) {
+ if (other_chunk->IsEmpty()) {
/* the "other" chunk was a music_chunk
which had only a tag, but no music
data - we cannot cross-fade that;
@@ -785,13 +816,16 @@ play_next_chunk(struct player *player)
/* play the current chunk */
+ GError *error = NULL;
if (!play_chunk(player->pc, player->song, chunk,
- &player->play_audio_format)) {
+ &player->play_audio_format, &error)) {
+ g_warning("%s", error->message);
+
music_buffer_return(player_buffer, chunk);
player_lock(pc);
- pc->error = PLAYER_ERROR_AUDIO;
+ pc_set_error(pc, PLAYER_ERROR_OUTPUT, error);
/* pause: the user may resume playback as soon as an
audio output becomes available */
@@ -862,21 +896,7 @@ player_song_border(struct player *player)
*/
static void do_play(struct player_control *pc, struct decoder_control *dc)
{
- struct player player = {
- .pc = pc,
- .dc = dc,
- .buffering = true,
- .decoder_starting = false,
- .paused = false,
- .queued = true,
- .output_open = false,
- .song = NULL,
- .xfade = XFADE_UNKNOWN,
- .cross_fading = false,
- .cross_fade_chunks = 0,
- .cross_fade_tag = NULL,
- .elapsed_time = 0.0,
- };
+ player player(pc, dc);
player_unlock(pc);
@@ -884,10 +904,12 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
player_dc_start(&player, player.pipe);
if (!player_wait_for_decoder(&player)) {
+ assert(player.song == NULL);
+
player_dc_stop(&player);
player_command_finished(pc);
music_pipe_free(player.pipe);
- event_pipe_emit(PIPE_EVENT_PLAYLIST);
+ GlobalEvents::Emit(GlobalEvents::PLAYLIST);
player_lock(pc);
return;
}
@@ -1049,10 +1071,14 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
if (player.cross_fade_tag != NULL)
tag_free(player.cross_fade_tag);
+ if (player.song != NULL)
+ song_free(player.song);
+
player_lock(pc);
if (player.queued) {
assert(pc->next_song != NULL);
+ song_free(pc->next_song);
pc->next_song = NULL;
}
@@ -1060,7 +1086,7 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
player_unlock(pc);
- event_pipe_emit(PIPE_EVENT_PLAYLIST);
+ GlobalEvents::Emit(GlobalEvents::PLAYLIST);
player_lock(pc);
}
@@ -1068,9 +1094,9 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
static gpointer
player_task(gpointer arg)
{
- struct player_control *pc = arg;
+ struct player_control *pc = (struct player_control *)arg;
- struct decoder_control *dc = dc_new(pc->cond);
+ struct decoder_control *dc = dc_new();
decoder_thread_start(dc);
player_buffer = music_buffer_new(pc->buffer_chunks);
@@ -1094,7 +1120,11 @@ player_task(gpointer arg)
/* fall through */
case PLAYER_COMMAND_PAUSE:
- pc->next_song = NULL;
+ if (pc->next_song != NULL) {
+ song_free(pc->next_song);
+ pc->next_song = NULL;
+ }
+
player_command_finished_locked(pc);
break;
@@ -1135,7 +1165,11 @@ player_task(gpointer arg)
return NULL;
case PLAYER_COMMAND_CANCEL:
- pc->next_song = NULL;
+ if (pc->next_song != NULL) {
+ song_free(pc->next_song);
+ pc->next_song = NULL;
+ }
+
player_command_finished_locked(pc);
break;