Commit b6995ca0 authored by Max Kellermann's avatar Max Kellermann

player_control: removed the global variable "pc"

Allocate a player_control object where needed, and pass it around. Each "client" object is associated with a "player_control" instance. This prepares multi-player support.
parent 715844fd
...@@ -27,11 +27,13 @@ ...@@ -27,11 +27,13 @@
struct client; struct client;
struct sockaddr; struct sockaddr;
struct player_control;
void client_manager_init(void); void client_manager_init(void);
void client_manager_deinit(void); void client_manager_deinit(void);
void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid); void client_new(struct player_control *player_control,
int fd, const struct sockaddr *sa, size_t sa_length, int uid);
bool client_is_expired(const struct client *client); bool client_is_expired(const struct client *client);
......
...@@ -32,6 +32,8 @@ struct deferred_buffer { ...@@ -32,6 +32,8 @@ struct deferred_buffer {
}; };
struct client { struct client {
struct player_control *player_control;
GIOChannel *channel; GIOChannel *channel;
guint source_id; guint source_id;
......
...@@ -41,12 +41,15 @@ ...@@ -41,12 +41,15 @@
static const char GREETING[] = "OK MPD " PROTOCOL_VERSION "\n"; static const char GREETING[] = "OK MPD " PROTOCOL_VERSION "\n";
void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid) void
client_new(struct player_control *player_control,
int fd, const struct sockaddr *sa, size_t sa_length, int uid)
{ {
static unsigned int next_client_num; static unsigned int next_client_num;
struct client *client; struct client *client;
char *remote; char *remote;
assert(player_control != NULL);
assert(fd >= 0); assert(fd >= 0);
#ifdef HAVE_LIBWRAP #ifdef HAVE_LIBWRAP
...@@ -81,6 +84,7 @@ void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid) ...@@ -81,6 +84,7 @@ void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid)
} }
client = g_new0(struct client, 1); client = g_new0(struct client, 1);
client->player_control = player_control;
#ifndef G_OS_WIN32 #ifndef G_OS_WIN32
client->channel = g_io_channel_unix_new(fd); client->channel = g_io_channel_unix_new(fd);
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "tag.h" #include "tag.h"
#include "strset.h" #include "strset.h"
#include "stored_playlist.h" #include "stored_playlist.h"
#include "client_internal.h"
#include <glib.h> #include <glib.h>
...@@ -166,9 +167,11 @@ int printAllIn(struct client *client, const char *name) ...@@ -166,9 +167,11 @@ int printAllIn(struct client *client, const char *name)
} }
static int static int
directoryAddSongToPlaylist(struct song *song, G_GNUC_UNUSED void *data) directoryAddSongToPlaylist(struct song *song, void *data)
{ {
return playlist_append_song(&g_playlist, song, NULL); struct player_control *pc = data;
return playlist_append_song(&g_playlist, pc, song, NULL);
} }
struct add_data { struct add_data {
...@@ -185,9 +188,10 @@ directoryAddSongToStoredPlaylist(struct song *song, void *_data) ...@@ -185,9 +188,10 @@ directoryAddSongToStoredPlaylist(struct song *song, void *_data)
return 0; return 0;
} }
int addAllIn(const char *name) int
addAllIn(struct player_control *pc, const char *name)
{ {
return db_walk(name, directoryAddSongToPlaylist, NULL, NULL); return db_walk(name, directoryAddSongToPlaylist, NULL, pc);
} }
int addAllInToStoredPlaylist(const char *name, const char *utf8file) int addAllInToStoredPlaylist(const char *name, const char *utf8file)
...@@ -205,7 +209,9 @@ findAddInDirectory(struct song *song, void *_data) ...@@ -205,7 +209,9 @@ findAddInDirectory(struct song *song, void *_data)
struct search_data *data = _data; struct search_data *data = _data;
if (locate_song_match(song, data->criteria)) if (locate_song_match(song, data->criteria))
return playlist_append_song(&g_playlist, song, NULL); return playlist_append_song(&g_playlist,
data->client->player_control,
song, NULL);
return 0; return 0;
} }
......
...@@ -22,10 +22,12 @@ ...@@ -22,10 +22,12 @@
struct client; struct client;
struct locate_item_list; struct locate_item_list;
struct player_control;
int printAllIn(struct client *client, const char *name); int printAllIn(struct client *client, const char *name);
int addAllIn(const char *name); int
addAllIn(struct player_control *pc, const char *name);
int addAllInToStoredPlaylist(const char *name, const char *utf8file); int addAllInToStoredPlaylist(const char *name, const char *utf8file);
......
...@@ -65,7 +65,7 @@ decoder_initialized(struct decoder *decoder, ...@@ -65,7 +65,7 @@ decoder_initialized(struct decoder *decoder,
dc->state = DECODE_STATE_DECODE; dc->state = DECODE_STATE_DECODE;
decoder_unlock(dc); decoder_unlock(dc);
player_lock_signal(); player_lock_signal(dc->player_control);
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),
...@@ -117,7 +117,7 @@ decoder_command_finished(struct decoder *decoder) ...@@ -117,7 +117,7 @@ decoder_command_finished(struct decoder *decoder)
dc->command = DECODE_COMMAND_NONE; dc->command = DECODE_COMMAND_NONE;
decoder_unlock(dc); decoder_unlock(dc);
player_lock_signal(); player_lock_signal(dc->player_control);
} }
double decoder_seek_where(G_GNUC_UNUSED struct decoder * decoder) double decoder_seek_where(G_GNUC_UNUSED struct decoder * decoder)
...@@ -214,7 +214,7 @@ do_send_tag(struct decoder *decoder, struct input_stream *is, ...@@ -214,7 +214,7 @@ do_send_tag(struct decoder *decoder, struct input_stream *is,
/* there is a partial chunk - flush it, we want the /* there is a partial chunk - flush it, we want the
tag in a new chunk */ tag in a new chunk */
decoder_flush_chunk(decoder); decoder_flush_chunk(decoder);
player_lock_signal(); player_lock_signal(decoder->dc->player_control);
} }
assert(decoder->chunk == NULL); assert(decoder->chunk == NULL);
...@@ -329,7 +329,7 @@ decoder_data(struct decoder *decoder, ...@@ -329,7 +329,7 @@ decoder_data(struct decoder *decoder,
if (dest == NULL) { if (dest == NULL) {
/* the chunk is full, flush it */ /* the chunk is full, flush it */
decoder_flush_chunk(decoder); decoder_flush_chunk(decoder);
player_lock_signal(); player_lock_signal(dc->player_control);
continue; continue;
} }
...@@ -348,7 +348,7 @@ decoder_data(struct decoder *decoder, ...@@ -348,7 +348,7 @@ decoder_data(struct decoder *decoder,
if (full) { if (full) {
/* the chunk is full, flush it */ /* the chunk is full, flush it */
decoder_flush_chunk(decoder); decoder_flush_chunk(decoder);
player_lock_signal(); player_lock_signal(dc->player_control);
} }
data += nbytes; data += nbytes;
...@@ -432,7 +432,7 @@ decoder_replay_gain(struct decoder *decoder, ...@@ -432,7 +432,7 @@ decoder_replay_gain(struct decoder *decoder,
replay gain values affect the following replay gain values affect the following
samples */ samples */
decoder_flush_chunk(decoder); decoder_flush_chunk(decoder);
player_lock_signal(); player_lock_signal(decoder->dc->player_control);
} }
} else } else
decoder->replay_gain_serial = 0; decoder->replay_gain_serial = 0;
......
...@@ -28,8 +28,9 @@ ...@@ -28,8 +28,9 @@
#define G_LOG_DOMAIN "decoder_control" #define G_LOG_DOMAIN "decoder_control"
void void
dc_init(struct decoder_control *dc) dc_init(struct decoder_control *dc, struct player_control *pc)
{ {
dc->player_control = pc;
dc->thread = NULL; dc->thread = NULL;
dc->mutex = g_mutex_new(); dc->mutex = g_mutex_new();
...@@ -62,7 +63,7 @@ static void ...@@ -62,7 +63,7 @@ static void
dc_command_wait_locked(struct decoder_control *dc) dc_command_wait_locked(struct decoder_control *dc)
{ {
while (dc->command != DECODE_COMMAND_NONE) while (dc->command != DECODE_COMMAND_NONE)
player_wait_decoder(dc); player_wait_decoder(dc->player_control, dc);
} }
void void
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include <assert.h> #include <assert.h>
struct player_control;
enum decoder_state { enum decoder_state {
DECODE_STATE_STOP = 0, DECODE_STATE_STOP = 0,
DECODE_STATE_START, DECODE_STATE_START,
...@@ -42,6 +44,12 @@ enum decoder_state { ...@@ -42,6 +44,12 @@ enum decoder_state {
}; };
struct decoder_control { struct decoder_control {
/**
* The player thread which calls us. This pointer is used to
* signal command completion.
*/
struct player_control *player_control;
/** the handle of the decoder thread, or NULL if the decoder /** the handle of the decoder thread, or NULL if the decoder
thread isn't running */ thread isn't running */
GThread *thread; GThread *thread;
...@@ -98,7 +106,7 @@ struct decoder_control { ...@@ -98,7 +106,7 @@ struct decoder_control {
}; };
void void
dc_init(struct decoder_control *dc); dc_init(struct decoder_control *dc, struct player_control *pc);
void void
dc_deinit(struct decoder_control *dc); dc_deinit(struct decoder_control *dc);
......
...@@ -65,7 +65,7 @@ need_chunks(struct decoder_control *dc, struct input_stream *is, bool do_wait) ...@@ -65,7 +65,7 @@ need_chunks(struct decoder_control *dc, struct input_stream *is, bool do_wait)
if ((is == NULL || !decoder_input_buffer(dc, is)) && do_wait) { if ((is == NULL || !decoder_input_buffer(dc, is)) && do_wait) {
decoder_wait(dc); decoder_wait(dc);
player_signal(); player_signal(dc->player_control);
return dc->command; return dc->command;
} }
......
...@@ -383,7 +383,7 @@ decoder_run_song(struct decoder_control *dc, ...@@ -383,7 +383,7 @@ decoder_run_song(struct decoder_control *dc,
dc->state = DECODE_STATE_START; dc->state = DECODE_STATE_START;
dc->command = DECODE_COMMAND_NONE; dc->command = DECODE_COMMAND_NONE;
player_signal(); player_signal(dc->player_control);
pcm_convert_init(&decoder.conv_state); pcm_convert_init(&decoder.conv_state);
...@@ -464,13 +464,13 @@ decoder_task(gpointer arg) ...@@ -464,13 +464,13 @@ decoder_task(gpointer arg)
dc->command = DECODE_COMMAND_NONE; dc->command = DECODE_COMMAND_NONE;
player_signal(); player_signal(dc->player_control);
break; break;
case DECODE_COMMAND_STOP: case DECODE_COMMAND_STOP:
dc->command = DECODE_COMMAND_NONE; dc->command = DECODE_COMMAND_NONE;
player_signal(); player_signal(dc->player_control);
break; break;
case DECODE_COMMAND_NONE: case DECODE_COMMAND_NONE:
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "client.h" #include "client.h"
#include "conf.h" #include "conf.h"
#include "glib_compat.h" #include "glib_compat.h"
#include "main.h"
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
...@@ -39,7 +40,7 @@ static void ...@@ -39,7 +40,7 @@ static void
listen_callback(int fd, const struct sockaddr *address, listen_callback(int fd, const struct sockaddr *address,
size_t address_length, int uid, G_GNUC_UNUSED void *ctx) size_t address_length, int uid, G_GNUC_UNUSED void *ctx)
{ {
client_new(fd, address, address_length, uid); client_new(global_player_control, fd, address, address_length, uid);
} }
static bool static bool
......
...@@ -94,6 +94,8 @@ GMainLoop *main_loop; ...@@ -94,6 +94,8 @@ GMainLoop *main_loop;
GCond *main_cond; GCond *main_cond;
struct player_control *global_player_control;
static void static void
glue_daemonize_init(const struct options *options) glue_daemonize_init(const struct options *options)
{ {
...@@ -183,7 +185,8 @@ glue_sticker_init(void) ...@@ -183,7 +185,8 @@ glue_sticker_init(void)
static void static void
glue_state_file_init(void) glue_state_file_init(void)
{ {
state_file_init(config_get_path(CONF_STATE_FILE)); state_file_init(config_get_path(CONF_STATE_FILE),
global_player_control);
} }
/** /**
...@@ -254,7 +257,7 @@ initialize_decoder_and_player(void) ...@@ -254,7 +257,7 @@ initialize_decoder_and_player(void)
if (buffered_before_play > buffered_chunks) if (buffered_before_play > buffered_chunks)
buffered_before_play = buffered_chunks; buffered_before_play = buffered_chunks;
pc_init(buffered_chunks, buffered_before_play); global_player_control = pc_new(buffered_chunks, buffered_before_play);
} }
/** /**
...@@ -364,7 +367,7 @@ int mpd_main(int argc, char *argv[]) ...@@ -364,7 +367,7 @@ int mpd_main(int argc, char *argv[])
initialize_decoder_and_player(); initialize_decoder_and_player();
volume_init(); volume_init();
initAudioConfig(); initAudioConfig();
audio_output_all_init(); audio_output_all_init(global_player_control);
client_manager_init(); client_manager_init();
replay_gain_global_init(); replay_gain_global_init();
...@@ -384,7 +387,7 @@ int mpd_main(int argc, char *argv[]) ...@@ -384,7 +387,7 @@ int mpd_main(int argc, char *argv[])
initZeroconf(); initZeroconf();
player_create(); player_create(global_player_control);
if (create_db) { if (create_db) {
/* the database failed to load: recreate the /* the database failed to load: recreate the
...@@ -410,7 +413,7 @@ int mpd_main(int argc, char *argv[]) ...@@ -410,7 +413,7 @@ int mpd_main(int argc, char *argv[])
/* enable all audio outputs (if not already done by /* enable all audio outputs (if not already done by
playlist_state_restore() */ playlist_state_restore() */
pc_update_audio(); pc_update_audio(global_player_control);
#ifdef WIN32 #ifdef WIN32
win32_app_started(); win32_app_started();
...@@ -431,8 +434,8 @@ int mpd_main(int argc, char *argv[]) ...@@ -431,8 +434,8 @@ int mpd_main(int argc, char *argv[])
mpd_inotify_finish(); mpd_inotify_finish();
#endif #endif
state_file_finish(); state_file_finish(global_player_control);
pc_kill(); pc_kill(global_player_control);
finishZeroconf(); finishZeroconf();
client_manager_deinit(); client_manager_deinit();
listen_global_finish(); listen_global_finish();
...@@ -457,7 +460,7 @@ int mpd_main(int argc, char *argv[]) ...@@ -457,7 +460,7 @@ int mpd_main(int argc, char *argv[])
mapper_finish(); mapper_finish();
path_global_finish(); path_global_finish();
finishPermissions(); finishPermissions();
pc_deinit(); pc_free(global_player_control);
command_finish(); command_finish();
update_global_finish(); update_global_finish();
decoder_plugin_deinit_all(); decoder_plugin_deinit_all();
......
...@@ -28,6 +28,8 @@ extern GMainLoop *main_loop; ...@@ -28,6 +28,8 @@ extern GMainLoop *main_loop;
extern GCond *main_cond; extern GCond *main_cond;
extern struct player_control *global_player_control;
/** /**
* A entry point for application. * A entry point for application.
* On non-Windows platforms this is called directly from main() * On non-Windows platforms this is called directly from main()
......
...@@ -100,7 +100,7 @@ audio_output_config_count(void) ...@@ -100,7 +100,7 @@ audio_output_config_count(void)
} }
void void
audio_output_all_init(void) audio_output_all_init(struct player_control *pc)
{ {
const struct config_param *param = NULL; const struct config_param *param = NULL;
unsigned int i; unsigned int i;
...@@ -121,7 +121,7 @@ audio_output_all_init(void) ...@@ -121,7 +121,7 @@ audio_output_all_init(void)
/* only allow param to be NULL if there just one audioOutput */ /* only allow param to be NULL if there just one audioOutput */
assert(param || (num_audio_outputs == 1)); assert(param || (num_audio_outputs == 1));
if (!audio_output_init(output, param, &error)) { if (!audio_output_init(output, param, pc, &error)) {
if (param != NULL) if (param != NULL)
MPD_ERROR("line %i: %s", MPD_ERROR("line %i: %s",
param->line, error->message); param->line, error->message);
...@@ -473,17 +473,17 @@ audio_output_all_check(void) ...@@ -473,17 +473,17 @@ audio_output_all_check(void)
} }
bool bool
audio_output_all_wait(unsigned threshold) audio_output_all_wait(struct player_control *pc, unsigned threshold)
{ {
player_lock(); player_lock(pc);
if (audio_output_all_check() < threshold) { if (audio_output_all_check() < threshold) {
player_unlock(); player_unlock(pc);
return true; return true;
} }
player_wait(); player_wait(pc);
player_unlock(); player_unlock(pc);
return audio_output_all_check() < threshold; return audio_output_all_check() < threshold;
} }
......
...@@ -32,13 +32,14 @@ ...@@ -32,13 +32,14 @@
struct audio_format; struct audio_format;
struct music_buffer; struct music_buffer;
struct music_chunk; struct music_chunk;
struct player_control;
/** /**
* Global initialization: load audio outputs from the configuration * Global initialization: load audio outputs from the configuration
* file and initialize them. * file and initialize them.
*/ */
void void
audio_output_all_init(void); audio_output_all_init(struct player_control *pc);
/** /**
* Global finalization: free memory occupied by audio outputs. All * Global finalization: free memory occupied by audio outputs. All
...@@ -127,7 +128,7 @@ audio_output_all_check(void); ...@@ -127,7 +128,7 @@ audio_output_all_check(void);
* @return true if there are less than #threshold chunks in the pipe * @return true if there are less than #threshold chunks in the pipe
*/ */
bool bool
audio_output_all_wait(unsigned threshold); audio_output_all_wait(struct player_control *pc, unsigned threshold);
/** /**
* Puts all audio outputs into pause mode. Most implementations will * Puts all audio outputs into pause mode. Most implementations will
......
...@@ -50,7 +50,7 @@ audio_output_enable_index(unsigned idx) ...@@ -50,7 +50,7 @@ audio_output_enable_index(unsigned idx)
ao->enabled = true; ao->enabled = true;
idle_add(IDLE_OUTPUT); idle_add(IDLE_OUTPUT);
pc_update_audio(); pc_update_audio(ao->player_control);
++audio_output_state_version; ++audio_output_state_version;
...@@ -79,7 +79,7 @@ audio_output_disable_index(unsigned idx) ...@@ -79,7 +79,7 @@ audio_output_disable_index(unsigned idx)
idle_add(IDLE_MIXER); idle_add(IDLE_MIXER);
} }
pc_update_audio(); pc_update_audio(ao->player_control);
++audio_output_state_version; ++audio_output_state_version;
......
...@@ -29,6 +29,7 @@ struct audio_output; ...@@ -29,6 +29,7 @@ struct audio_output;
struct audio_format; struct audio_format;
struct config_param; struct config_param;
struct music_pipe; struct music_pipe;
struct player_control;
static inline GQuark static inline GQuark
audio_output_quark(void) audio_output_quark(void)
...@@ -38,6 +39,7 @@ audio_output_quark(void) ...@@ -38,6 +39,7 @@ audio_output_quark(void)
bool bool
audio_output_init(struct audio_output *ao, const struct config_param *param, audio_output_init(struct audio_output *ao, const struct config_param *param,
struct player_control *pc,
GError **error_r); GError **error_r);
/** /**
......
...@@ -127,8 +127,12 @@ audio_output_load_mixer(void *ao, const struct config_param *param, ...@@ -127,8 +127,12 @@ audio_output_load_mixer(void *ao, const struct config_param *param,
bool bool
audio_output_init(struct audio_output *ao, const struct config_param *param, audio_output_init(struct audio_output *ao, const struct config_param *param,
struct player_control *pc,
GError **error_r) GError **error_r)
{ {
assert(ao != NULL);
assert(pc != NULL);
const struct audio_output_plugin *plugin = NULL; const struct audio_output_plugin *plugin = NULL;
GError *error = NULL; GError *error = NULL;
...@@ -249,6 +253,7 @@ audio_output_init(struct audio_output *ao, const struct config_param *param, ...@@ -249,6 +253,7 @@ audio_output_init(struct audio_output *ao, const struct config_param *param,
ao->command = AO_COMMAND_NONE; ao->command = AO_COMMAND_NONE;
ao->mutex = g_mutex_new(); ao->mutex = g_mutex_new();
ao->cond = g_cond_new(); ao->cond = g_cond_new();
ao->player_control = pc;
ao->data = ao_plugin_init(plugin, ao->data = ao_plugin_init(plugin,
&ao->config_audio_format, &ao->config_audio_format,
......
...@@ -208,6 +208,12 @@ struct audio_output { ...@@ -208,6 +208,12 @@ struct audio_output {
GCond *cond; GCond *cond;
/** /**
* The player_control object which "owns" this output. This
* object is needed to signal command completion.
*/
struct player_control *player_control;
/**
* The #music_chunk which is currently being played. All * The #music_chunk which is currently being played. All
* chunks before this one may be returned to the * chunks before this one may be returned to the
* #music_buffer, because they are not going to be used by * #music_buffer, because they are not going to be used by
......
...@@ -530,7 +530,7 @@ ao_play(struct audio_output *ao) ...@@ -530,7 +530,7 @@ ao_play(struct audio_output *ao)
ao->chunk_finished = true; ao->chunk_finished = true;
g_mutex_unlock(ao->mutex); g_mutex_unlock(ao->mutex);
player_lock_signal(); player_lock_signal(ao->player_control);
g_mutex_lock(ao->mutex); g_mutex_lock(ao->mutex);
return true; return true;
......
...@@ -116,28 +116,28 @@ struct player_control { ...@@ -116,28 +116,28 @@ struct player_control {
double total_play_time; double total_play_time;
}; };
extern struct player_control pc; struct player_control *
pc_new(unsigned buffer_chunks, unsigned buffered_before_play);
void pc_init(unsigned buffer_chunks, unsigned buffered_before_play); void
pc_free(struct player_control *pc);
void pc_deinit(void);
/** /**
* Locks the #player_control object. * Locks the #player_control object.
*/ */
static inline void static inline void
player_lock(void) player_lock(struct player_control *pc)
{ {
g_mutex_lock(pc.mutex); g_mutex_lock(pc->mutex);
} }
/** /**
* Unlocks the #player_control object. * Unlocks the #player_control object.
*/ */
static inline void static inline void
player_unlock(void) player_unlock(struct player_control *pc)
{ {
g_mutex_unlock(pc.mutex); g_mutex_unlock(pc->mutex);
} }
/** /**
...@@ -146,9 +146,9 @@ player_unlock(void) ...@@ -146,9 +146,9 @@ player_unlock(void)
* to calling this function. * to calling this function.
*/ */
static inline void static inline void
player_wait(void) player_wait(struct player_control *pc)
{ {
g_cond_wait(pc.cond, pc.mutex); g_cond_wait(pc->cond, pc->mutex);
} }
/** /**
...@@ -159,16 +159,16 @@ player_wait(void) ...@@ -159,16 +159,16 @@ player_wait(void)
* Note the small difference to the player_wait() function! * Note the small difference to the player_wait() function!
*/ */
void void
player_wait_decoder(struct decoder_control *dc); player_wait_decoder(struct player_control *pc, struct decoder_control *dc);
/** /**
* Signals the #player_control object. The object should be locked * Signals the #player_control object. The object should be locked
* prior to calling this function. * prior to calling this function.
*/ */
static inline void static inline void
player_signal(void) player_signal(struct player_control *pc)
{ {
g_cond_signal(pc.cond); g_cond_signal(pc->cond);
} }
/** /**
...@@ -176,11 +176,11 @@ player_signal(void) ...@@ -176,11 +176,11 @@ player_signal(void)
* locked by this function. * locked by this function.
*/ */
static inline void static inline void
player_lock_signal(void) player_lock_signal(struct player_control *pc)
{ {
player_lock(); player_lock(pc);
player_signal(); player_signal(pc);
player_unlock(); player_unlock(pc);
} }
/** /**
...@@ -189,33 +189,34 @@ player_lock_signal(void) ...@@ -189,33 +189,34 @@ player_lock_signal(void)
* not point to an invalid pointer. * not point to an invalid pointer.
*/ */
void void
pc_song_deleted(const struct song *song); pc_song_deleted(struct player_control *pc, const struct song *song);
void void
pc_play(struct song *song); pc_play(struct player_control *pc, struct song *song);
/** /**
* see PLAYER_COMMAND_CANCEL * see PLAYER_COMMAND_CANCEL
*/ */
void pc_cancel(void); void
pc_cancel(struct player_control *pc);
void void
pc_set_pause(bool pause_flag); pc_set_pause(struct player_control *pc, bool pause_flag);
void void
pc_pause(void); pc_pause(struct player_control *pc);
void void
pc_kill(void); pc_kill(struct player_control *pc);
void void
pc_get_status(struct player_status *status); pc_get_status(struct player_control *pc, struct player_status *status);
enum player_state enum player_state
pc_get_state(void); pc_get_state(struct player_control *pc);
void void
pc_clear_error(void); pc_clear_error(struct player_control *pc);
/** /**
* Returns the human-readable message describing the last error during * Returns the human-readable message describing the last error during
...@@ -223,19 +224,19 @@ pc_clear_error(void); ...@@ -223,19 +224,19 @@ pc_clear_error(void);
* returned string. * returned string.
*/ */
char * char *
pc_get_error_message(void); pc_get_error_message(struct player_control *pc);
enum player_error enum player_error
pc_get_error(void); pc_get_error(struct player_control *pc);
void void
pc_stop(void); pc_stop(struct player_control *pc);
void void
pc_update_audio(void); pc_update_audio(struct player_control *pc);
void void
pc_enqueue_song(struct song *song); pc_enqueue_song(struct player_control *pc, struct song *song);
/** /**
* Makes the player thread seek the specified song to a position. * Makes the player thread seek the specified song to a position.
...@@ -244,27 +245,27 @@ pc_enqueue_song(struct song *song); ...@@ -244,27 +245,27 @@ pc_enqueue_song(struct song *song);
* playing currently) * playing currently)
*/ */
bool bool
pc_seek(struct song *song, float seek_time); pc_seek(struct player_control *pc, struct song *song, float seek_time);
void void
pc_set_cross_fade(float cross_fade_seconds); pc_set_cross_fade(struct player_control *pc, float cross_fade_seconds);
float float
pc_get_cross_fade(void); pc_get_cross_fade(const struct player_control *pc);
void void
pc_set_mixramp_db(float mixramp_db); pc_set_mixramp_db(struct player_control *pc, float mixramp_db);
float float
pc_get_mixramp_db(void); pc_get_mixramp_db(const struct player_control *pc);
void void
pc_set_mixramp_delay(float mixramp_delay_seconds); pc_set_mixramp_delay(struct player_control *pc, float mixramp_delay_seconds);
float float
pc_get_mixramp_delay(void); pc_get_mixramp_delay(const struct player_control *pc);
double double
pc_get_total_play_time(void); pc_get_total_play_time(const struct player_control *pc);
#endif #endif
...@@ -37,6 +37,9 @@ ...@@ -37,6 +37,9 @@
#ifndef MPD_PLAYER_THREAD_H #ifndef MPD_PLAYER_THREAD_H
#define MPD_PLAYER_THREAD_H #define MPD_PLAYER_THREAD_H
void player_create(void); struct player_control;
void
player_create(struct player_control *pc);
#endif #endif
...@@ -75,7 +75,8 @@ playlist_finish(struct playlist *playlist) ...@@ -75,7 +75,8 @@ playlist_finish(struct playlist *playlist)
* Queue a song, addressed by its order number. * Queue a song, addressed by its order number.
*/ */
static void static void
playlist_queue_song_order(struct playlist *playlist, unsigned order) playlist_queue_song_order(struct playlist *playlist, struct player_control *pc,
unsigned order)
{ {
struct song *song; struct song *song;
char *uri; char *uri;
...@@ -89,16 +90,16 @@ playlist_queue_song_order(struct playlist *playlist, unsigned order) ...@@ -89,16 +90,16 @@ playlist_queue_song_order(struct playlist *playlist, unsigned order)
g_debug("queue song %i:\"%s\"", playlist->queued, uri); g_debug("queue song %i:\"%s\"", playlist->queued, uri);
g_free(uri); g_free(uri);
pc_enqueue_song(song); pc_enqueue_song(pc, song);
} }
/** /**
* Called if the player thread has started playing the "queued" song. * Called if the player thread has started playing the "queued" song.
*/ */
static void static void
playlist_song_started(struct playlist *playlist) playlist_song_started(struct playlist *playlist, struct player_control *pc)
{ {
assert(pc.next_song == NULL); assert(pc->next_song == NULL);
assert(playlist->queued >= -1); assert(playlist->queued >= -1);
/* queued song has started: copy queued to current, /* queued song has started: copy queued to current,
...@@ -110,11 +111,13 @@ playlist_song_started(struct playlist *playlist) ...@@ -110,11 +111,13 @@ playlist_song_started(struct playlist *playlist)
/* Pause if we are in single mode. */ /* Pause if we are in single mode. */
if(playlist->queue.single && !playlist->queue.repeat) { if(playlist->queue.single && !playlist->queue.repeat) {
pc_set_pause(true); pc_set_pause(pc, true);
} }
if(playlist->queue.consume) if(playlist->queue.consume)
playlist_delete(playlist, queue_order_to_position(&playlist->queue, current)); playlist_delete(playlist, pc,
queue_order_to_position(&playlist->queue,
current));
idle_add(IDLE_PLAYER); idle_add(IDLE_PLAYER);
} }
...@@ -129,7 +132,9 @@ playlist_get_queued_song(struct playlist *playlist) ...@@ -129,7 +132,9 @@ playlist_get_queued_song(struct playlist *playlist)
} }
void void
playlist_update_queued_song(struct playlist *playlist, const struct song *prev) playlist_update_queued_song(struct playlist *playlist,
struct player_control *pc,
const struct song *prev)
{ {
int next_order; int next_order;
const struct song *next_song; const struct song *next_song;
...@@ -170,20 +175,21 @@ playlist_update_queued_song(struct playlist *playlist, const struct song *prev) ...@@ -170,20 +175,21 @@ playlist_update_queued_song(struct playlist *playlist, const struct song *prev)
if (prev != NULL && next_song != prev) { if (prev != NULL && next_song != prev) {
/* clear the currently queued song */ /* clear the currently queued song */
pc_cancel(); pc_cancel(pc);
playlist->queued = -1; playlist->queued = -1;
} }
if (next_order >= 0) { if (next_order >= 0) {
if (next_song != prev) if (next_song != prev)
playlist_queue_song_order(playlist, next_order); playlist_queue_song_order(playlist, pc, next_order);
else else
playlist->queued = next_order; playlist->queued = next_order;
} }
} }
void void
playlist_play_order(struct playlist *playlist, int orderNum) playlist_play_order(struct playlist *playlist, struct player_control *pc,
int orderNum)
{ {
struct song *song; struct song *song;
char *uri; char *uri;
...@@ -197,46 +203,46 @@ playlist_play_order(struct playlist *playlist, int orderNum) ...@@ -197,46 +203,46 @@ playlist_play_order(struct playlist *playlist, int orderNum)
g_debug("play %i:\"%s\"", orderNum, uri); g_debug("play %i:\"%s\"", orderNum, uri);
g_free(uri); g_free(uri);
pc_play(song); pc_play(pc, song);
playlist->current = orderNum; playlist->current = orderNum;
} }
static void static void
playlist_resume_playback(struct playlist *playlist); playlist_resume_playback(struct playlist *playlist, struct player_control *pc);
/** /**
* This is the "PLAYLIST" event handler. It is invoked by the player * This is the "PLAYLIST" event handler. It is invoked by the player
* thread whenever it requests a new queued song, or when it exits. * thread whenever it requests a new queued song, or when it exits.
*/ */
void void
playlist_sync(struct playlist *playlist) playlist_sync(struct playlist *playlist, struct player_control *pc)
{ {
if (!playlist->playing) if (!playlist->playing)
/* this event has reached us out of sync: we aren't /* this event has reached us out of sync: we aren't
playing anymore; ignore the event */ playing anymore; ignore the event */
return; return;
player_lock(); player_lock(pc);
enum player_state pc_state = pc_get_state(); enum player_state pc_state = pc_get_state(pc);
const struct song *pc_next_song = pc.next_song; const struct song *pc_next_song = pc->next_song;
player_unlock(); player_unlock(pc);
if (pc_state == PLAYER_STATE_STOP) if (pc_state == PLAYER_STATE_STOP)
/* the player thread has stopped: check if playback /* the player thread has stopped: check if playback
should be restarted with the next song. That can should be restarted with the next song. That can
happen if the playlist isn't filling the queue fast happen if the playlist isn't filling the queue fast
enough */ enough */
playlist_resume_playback(playlist); playlist_resume_playback(playlist, pc);
else { else {
/* check if the player thread has already started /* check if the player thread has already started
playing the queued song */ playing the queued song */
if (pc_next_song == NULL && playlist->queued != -1) if (pc_next_song == NULL && playlist->queued != -1)
playlist_song_started(playlist); playlist_song_started(playlist, pc);
/* make sure the queued song is always set (if /* make sure the queued song is always set (if
possible) */ possible) */
if (pc.next_song == NULL && playlist->queued < 0) if (pc->next_song == NULL && playlist->queued < 0)
playlist_update_queued_song(playlist, NULL); playlist_update_queued_song(playlist, pc, NULL);
} }
} }
...@@ -245,14 +251,14 @@ playlist_sync(struct playlist *playlist) ...@@ -245,14 +251,14 @@ playlist_sync(struct playlist *playlist)
* decide whether to re-start playback * decide whether to re-start playback
*/ */
static void static void
playlist_resume_playback(struct playlist *playlist) playlist_resume_playback(struct playlist *playlist, struct player_control *pc)
{ {
enum player_error error; enum player_error error;
assert(playlist->playing); assert(playlist->playing);
assert(pc_get_state() == PLAYER_STATE_STOP); assert(pc_get_state(pc) == PLAYER_STATE_STOP);
error = pc_get_error(); error = pc_get_error(pc);
if (error == PLAYER_ERROR_NOERROR) if (error == PLAYER_ERROR_NOERROR)
playlist->error_count = 0; playlist->error_count = 0;
else else
...@@ -263,10 +269,10 @@ playlist_resume_playback(struct playlist *playlist) ...@@ -263,10 +269,10 @@ playlist_resume_playback(struct playlist *playlist)
playlist->error_count >= queue_length(&playlist->queue)) playlist->error_count >= queue_length(&playlist->queue))
/* too many errors, or critical error: stop /* too many errors, or critical error: stop
playback */ playback */
playlist_stop(playlist); playlist_stop(playlist, pc);
else else
/* continue playback at the next song */ /* continue playback at the next song */
playlist_next(playlist); playlist_next(playlist, pc);
} }
bool bool
...@@ -294,7 +300,8 @@ playlist_get_consume(const struct playlist *playlist) ...@@ -294,7 +300,8 @@ playlist_get_consume(const struct playlist *playlist)
} }
void void
playlist_set_repeat(struct playlist *playlist, bool status) playlist_set_repeat(struct playlist *playlist, struct player_control *pc,
bool status)
{ {
if (status == playlist->queue.repeat) if (status == playlist->queue.repeat)
return; return;
...@@ -303,7 +310,7 @@ playlist_set_repeat(struct playlist *playlist, bool status) ...@@ -303,7 +310,7 @@ playlist_set_repeat(struct playlist *playlist, bool status)
/* if the last song is currently being played, the "next song" /* if the last song is currently being played, the "next song"
might change when repeat mode is toggled */ might change when repeat mode is toggled */
playlist_update_queued_song(playlist, playlist_update_queued_song(playlist, pc,
playlist_get_queued_song(playlist)); playlist_get_queued_song(playlist));
idle_add(IDLE_OPTIONS); idle_add(IDLE_OPTIONS);
...@@ -321,7 +328,8 @@ playlist_order(struct playlist *playlist) ...@@ -321,7 +328,8 @@ playlist_order(struct playlist *playlist)
} }
void void
playlist_set_single(struct playlist *playlist, bool status) playlist_set_single(struct playlist *playlist, struct player_control *pc,
bool status)
{ {
if (status == playlist->queue.single) if (status == playlist->queue.single)
return; return;
...@@ -330,7 +338,7 @@ playlist_set_single(struct playlist *playlist, bool status) ...@@ -330,7 +338,7 @@ playlist_set_single(struct playlist *playlist, bool status)
/* if the last song is currently being played, the "next song" /* if the last song is currently being played, the "next song"
might change when single mode is toggled */ might change when single mode is toggled */
playlist_update_queued_song(playlist, playlist_update_queued_song(playlist, pc,
playlist_get_queued_song(playlist)); playlist_get_queued_song(playlist));
idle_add(IDLE_OPTIONS); idle_add(IDLE_OPTIONS);
...@@ -347,7 +355,8 @@ playlist_set_consume(struct playlist *playlist, bool status) ...@@ -347,7 +355,8 @@ playlist_set_consume(struct playlist *playlist, bool status)
} }
void void
playlist_set_random(struct playlist *playlist, bool status) playlist_set_random(struct playlist *playlist, struct player_control *pc,
bool status)
{ {
const struct song *queued; const struct song *queued;
...@@ -384,7 +393,7 @@ playlist_set_random(struct playlist *playlist, bool status) ...@@ -384,7 +393,7 @@ playlist_set_random(struct playlist *playlist, bool status)
} else } else
playlist_order(playlist); playlist_order(playlist);
playlist_update_queued_song(playlist, queued); playlist_update_queued_song(playlist, pc, queued);
idle_add(IDLE_OPTIONS); idle_add(IDLE_OPTIONS);
} }
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#define PLAYLIST_COMMENT '#' #define PLAYLIST_COMMENT '#'
struct player_control;
enum playlist_result { enum playlist_result {
PLAYLIST_RESULT_SUCCESS, PLAYLIST_RESULT_SUCCESS,
PLAYLIST_RESULT_ERRNO, PLAYLIST_RESULT_ERRNO,
...@@ -111,7 +113,7 @@ playlist_get_queue(const struct playlist *playlist) ...@@ -111,7 +113,7 @@ playlist_get_queue(const struct playlist *playlist)
} }
void void
playlist_clear(struct playlist *playlist); playlist_clear(struct playlist *playlist, struct player_control *pc);
#ifndef WIN32 #ifndef WIN32
/** /**
...@@ -119,20 +121,21 @@ playlist_clear(struct playlist *playlist); ...@@ -119,20 +121,21 @@ playlist_clear(struct playlist *playlist);
* but only if the file's owner is equal to the specified uid. * but only if the file's owner is equal to the specified uid.
*/ */
enum playlist_result enum playlist_result
playlist_append_file(struct playlist *playlist, const char *path, int uid, playlist_append_file(struct playlist *playlist, struct player_control *pc,
unsigned *added_id); const char *path, int uid, unsigned *added_id);
#endif #endif
enum playlist_result enum playlist_result
playlist_append_uri(struct playlist *playlist, const char *file, playlist_append_uri(struct playlist *playlist, struct player_control *pc,
unsigned *added_id); const char *file, unsigned *added_id);
enum playlist_result enum playlist_result
playlist_append_song(struct playlist *playlist, playlist_append_song(struct playlist *playlist, struct player_control *pc,
struct song *song, unsigned *added_id); struct song *song, unsigned *added_id);
enum playlist_result enum playlist_result
playlist_delete(struct playlist *playlist, unsigned song); playlist_delete(struct playlist *playlist, struct player_control *pc,
unsigned song);
/** /**
* Deletes a range of songs from the playlist. * Deletes a range of songs from the playlist.
...@@ -141,64 +144,77 @@ playlist_delete(struct playlist *playlist, unsigned song); ...@@ -141,64 +144,77 @@ playlist_delete(struct playlist *playlist, unsigned song);
* @param end the position after the last song to delete * @param end the position after the last song to delete
*/ */
enum playlist_result enum playlist_result
playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end); playlist_delete_range(struct playlist *playlist, struct player_control *pc,
unsigned start, unsigned end);
enum playlist_result enum playlist_result
playlist_delete_id(struct playlist *playlist, unsigned song); playlist_delete_id(struct playlist *playlist, struct player_control *pc,
unsigned song);
void void
playlist_stop(struct playlist *playlist); playlist_stop(struct playlist *playlist, struct player_control *pc);
enum playlist_result enum playlist_result
playlist_play(struct playlist *playlist, int song); playlist_play(struct playlist *playlist, struct player_control *pc,
int song);
enum playlist_result enum playlist_result
playlist_play_id(struct playlist *playlist, int song); playlist_play_id(struct playlist *playlist, struct player_control *pc,
int song);
void void
playlist_next(struct playlist *playlist); playlist_next(struct playlist *playlist, struct player_control *pc);
void void
playlist_sync(struct playlist *playlist); playlist_sync(struct playlist *playlist, struct player_control *pc);
void void
playlist_previous(struct playlist *playlist); playlist_previous(struct playlist *playlist, struct player_control *pc);
void void
playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end); playlist_shuffle(struct playlist *playlist, struct player_control *pc,
unsigned start, unsigned end);
void void
playlist_delete_song(struct playlist *playlist, const struct song *song); playlist_delete_song(struct playlist *playlist, struct player_control *pc,
const struct song *song);
enum playlist_result enum playlist_result
playlist_move_range(struct playlist *playlist, unsigned start, unsigned end, int to); playlist_move_range(struct playlist *playlist, struct player_control *pc,
unsigned start, unsigned end, int to);
enum playlist_result enum playlist_result
playlist_move_id(struct playlist *playlist, unsigned id, int to); playlist_move_id(struct playlist *playlist, struct player_control *pc,
unsigned id, int to);
enum playlist_result enum playlist_result
playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2); playlist_swap_songs(struct playlist *playlist, struct player_control *pc,
unsigned song1, unsigned song2);
enum playlist_result enum playlist_result
playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2); playlist_swap_songs_id(struct playlist *playlist, struct player_control *pc,
unsigned id1, unsigned id2);
bool bool
playlist_get_repeat(const struct playlist *playlist); playlist_get_repeat(const struct playlist *playlist);
void void
playlist_set_repeat(struct playlist *playlist, bool status); playlist_set_repeat(struct playlist *playlist, struct player_control *pc,
bool status);
bool bool
playlist_get_random(const struct playlist *playlist); playlist_get_random(const struct playlist *playlist);
void void
playlist_set_random(struct playlist *playlist, bool status); playlist_set_random(struct playlist *playlist, struct player_control *pc,
bool status);
bool bool
playlist_get_single(const struct playlist *playlist); playlist_get_single(const struct playlist *playlist);
void void
playlist_set_single(struct playlist *playlist, bool status); playlist_set_single(struct playlist *playlist, struct player_control *pc,
bool status);
bool bool
playlist_get_consume(const struct playlist *playlist); playlist_get_consume(const struct playlist *playlist);
...@@ -222,10 +238,11 @@ unsigned long ...@@ -222,10 +238,11 @@ unsigned long
playlist_get_version(const struct playlist *playlist); playlist_get_version(const struct playlist *playlist);
enum playlist_result enum playlist_result
playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time); playlist_seek_song(struct playlist *playlist, struct player_control *pc,
unsigned song, float seek_time);
enum playlist_result enum playlist_result
playlist_seek_song_id(struct playlist *playlist, playlist_seek_song_id(struct playlist *playlist, struct player_control *pc,
unsigned id, float seek_time); unsigned id, float seek_time);
void void
......
...@@ -32,7 +32,8 @@ ...@@ -32,7 +32,8 @@
#undef G_LOG_DOMAIN #undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "playlist" #define G_LOG_DOMAIN "playlist"
void playlist_stop(struct playlist *playlist) void
playlist_stop(struct playlist *playlist, struct player_control *pc)
{ {
if (!playlist->playing) if (!playlist->playing)
return; return;
...@@ -40,7 +41,7 @@ void playlist_stop(struct playlist *playlist) ...@@ -40,7 +41,7 @@ void playlist_stop(struct playlist *playlist)
assert(playlist->current >= 0); assert(playlist->current >= 0);
g_debug("stop"); g_debug("stop");
pc_stop(); pc_stop(pc);
playlist->queued = -1; playlist->queued = -1;
playlist->playing = false; playlist->playing = false;
...@@ -62,11 +63,13 @@ void playlist_stop(struct playlist *playlist) ...@@ -62,11 +63,13 @@ void playlist_stop(struct playlist *playlist)
} }
} }
enum playlist_result playlist_play(struct playlist *playlist, int song) enum playlist_result
playlist_play(struct playlist *playlist, struct player_control *pc,
int song)
{ {
unsigned i = song; unsigned i = song;
pc_clear_error(); pc_clear_error(pc);
if (song == -1) { if (song == -1) {
/* play any song ("current" song, or the first song */ /* play any song ("current" song, or the first song */
...@@ -77,7 +80,7 @@ enum playlist_result playlist_play(struct playlist *playlist, int song) ...@@ -77,7 +80,7 @@ enum playlist_result playlist_play(struct playlist *playlist, int song)
if (playlist->playing) { if (playlist->playing) {
/* already playing: unpause playback, just in /* already playing: unpause playback, just in
case it was paused, and return */ case it was paused, and return */
pc_set_pause(false); pc_set_pause(pc, false);
return PLAYLIST_RESULT_SUCCESS; return PLAYLIST_RESULT_SUCCESS;
} }
...@@ -109,28 +112,29 @@ enum playlist_result playlist_play(struct playlist *playlist, int song) ...@@ -109,28 +112,29 @@ enum playlist_result playlist_play(struct playlist *playlist, int song)
playlist->stop_on_error = false; playlist->stop_on_error = false;
playlist->error_count = 0; playlist->error_count = 0;
playlist_play_order(playlist, i); playlist_play_order(playlist, pc, i);
return PLAYLIST_RESULT_SUCCESS; return PLAYLIST_RESULT_SUCCESS;
} }
enum playlist_result enum playlist_result
playlist_play_id(struct playlist *playlist, int id) playlist_play_id(struct playlist *playlist, struct player_control *pc,
int id)
{ {
int song; int song;
if (id == -1) { if (id == -1) {
return playlist_play(playlist, id); return playlist_play(playlist, pc, id);
} }
song = queue_id_to_position(&playlist->queue, id); song = queue_id_to_position(&playlist->queue, id);
if (song < 0) if (song < 0)
return PLAYLIST_RESULT_NO_SUCH_SONG; return PLAYLIST_RESULT_NO_SUCH_SONG;
return playlist_play(playlist, song); return playlist_play(playlist, pc, song);
} }
void void
playlist_next(struct playlist *playlist) playlist_next(struct playlist *playlist, struct player_control *pc)
{ {
int next_order; int next_order;
int current; int current;
...@@ -149,7 +153,7 @@ playlist_next(struct playlist *playlist) ...@@ -149,7 +153,7 @@ playlist_next(struct playlist *playlist)
next_order = queue_next_order(&playlist->queue, playlist->current); next_order = queue_next_order(&playlist->queue, playlist->current);
if (next_order < 0) { if (next_order < 0) {
/* no song after this one: stop playback */ /* no song after this one: stop playback */
playlist_stop(playlist); playlist_stop(playlist, pc);
/* reset "current song" */ /* reset "current song" */
playlist->current = -1; playlist->current = -1;
...@@ -170,15 +174,18 @@ playlist_next(struct playlist *playlist) ...@@ -170,15 +174,18 @@ playlist_next(struct playlist *playlist)
discard them anyway */ discard them anyway */
} }
playlist_play_order(playlist, next_order); playlist_play_order(playlist, pc, next_order);
} }
/* Consume mode removes each played songs. */ /* Consume mode removes each played songs. */
if(playlist->queue.consume) if(playlist->queue.consume)
playlist_delete(playlist, queue_order_to_position(&playlist->queue, current)); playlist_delete(playlist, pc,
queue_order_to_position(&playlist->queue,
current));
} }
void playlist_previous(struct playlist *playlist) void
playlist_previous(struct playlist *playlist, struct player_control *pc)
{ {
if (!playlist->playing) if (!playlist->playing)
return; return;
...@@ -187,21 +194,22 @@ void playlist_previous(struct playlist *playlist) ...@@ -187,21 +194,22 @@ void playlist_previous(struct playlist *playlist)
if (playlist->current > 0) { if (playlist->current > 0) {
/* play the preceding song */ /* play the preceding song */
playlist_play_order(playlist, playlist_play_order(playlist, pc,
playlist->current - 1); playlist->current - 1);
} else if (playlist->queue.repeat) { } else if (playlist->queue.repeat) {
/* play the last song in "repeat" mode */ /* play the last song in "repeat" mode */
playlist_play_order(playlist, playlist_play_order(playlist, pc,
queue_length(&playlist->queue) - 1); queue_length(&playlist->queue) - 1);
} else { } else {
/* re-start playing the current song if it's /* re-start playing the current song if it's
the first one */ the first one */
playlist_play_order(playlist, playlist->current); playlist_play_order(playlist, pc, playlist->current);
} }
} }
enum playlist_result enum playlist_result
playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time) playlist_seek_song(struct playlist *playlist, struct player_control *pc,
unsigned song, float seek_time)
{ {
const struct song *queued; const struct song *queued;
unsigned i; unsigned i;
...@@ -217,7 +225,7 @@ playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time) ...@@ -217,7 +225,7 @@ playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time)
else else
i = song; i = song;
pc_clear_error(); pc_clear_error(pc);
playlist->stop_on_error = true; playlist->stop_on_error = true;
playlist->error_count = 0; playlist->error_count = 0;
...@@ -225,29 +233,30 @@ playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time) ...@@ -225,29 +233,30 @@ playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time)
/* seeking is not within the current song - first /* seeking is not within the current song - first
start playing the new song */ start playing the new song */
playlist_play_order(playlist, i); playlist_play_order(playlist, pc, i);
queued = NULL; queued = NULL;
} }
success = pc_seek(queue_get_order(&playlist->queue, i), seek_time); success = pc_seek(pc, queue_get_order(&playlist->queue, i), seek_time);
if (!success) { if (!success) {
playlist_update_queued_song(playlist, queued); playlist_update_queued_song(playlist, pc, queued);
return PLAYLIST_RESULT_NOT_PLAYING; return PLAYLIST_RESULT_NOT_PLAYING;
} }
playlist->queued = -1; playlist->queued = -1;
playlist_update_queued_song(playlist, NULL); playlist_update_queued_song(playlist, pc, NULL);
return PLAYLIST_RESULT_SUCCESS; return PLAYLIST_RESULT_SUCCESS;
} }
enum playlist_result enum playlist_result
playlist_seek_song_id(struct playlist *playlist, unsigned id, float seek_time) playlist_seek_song_id(struct playlist *playlist, struct player_control *pc,
unsigned id, float seek_time)
{ {
int song = queue_id_to_position(&playlist->queue, id); int song = queue_id_to_position(&playlist->queue, id);
if (song < 0) if (song < 0)
return PLAYLIST_RESULT_NO_SUCH_SONG; return PLAYLIST_RESULT_NO_SUCH_SONG;
return playlist_seek_song(playlist, song, seek_time); return playlist_seek_song(playlist, pc, song, seek_time);
} }
...@@ -43,16 +43,17 @@ static void playlist_increment_version(struct playlist *playlist) ...@@ -43,16 +43,17 @@ static void playlist_increment_version(struct playlist *playlist)
idle_add(IDLE_PLAYLIST); idle_add(IDLE_PLAYLIST);
} }
void playlist_clear(struct playlist *playlist) void
playlist_clear(struct playlist *playlist, struct player_control *pc)
{ {
playlist_stop(playlist); playlist_stop(playlist, pc);
/* make sure there are no references to allocated songs /* make sure there are no references to allocated songs
anymore */ anymore */
for (unsigned i = 0; i < queue_length(&playlist->queue); i++) { for (unsigned i = 0; i < queue_length(&playlist->queue); i++) {
const struct song *song = queue_get(&playlist->queue, i); const struct song *song = queue_get(&playlist->queue, i);
if (!song_in_database(song)) if (!song_in_database(song))
pc_song_deleted(song); pc_song_deleted(pc, song);
} }
queue_clear(&playlist->queue); queue_clear(&playlist->queue);
...@@ -64,8 +65,8 @@ void playlist_clear(struct playlist *playlist) ...@@ -64,8 +65,8 @@ void playlist_clear(struct playlist *playlist)
#ifndef WIN32 #ifndef WIN32
enum playlist_result enum playlist_result
playlist_append_file(struct playlist *playlist, const char *path, int uid, playlist_append_file(struct playlist *playlist, struct player_control *pc,
unsigned *added_id) const char *path, int uid, unsigned *added_id)
{ {
int ret; int ret;
struct stat st; struct stat st;
...@@ -87,12 +88,12 @@ playlist_append_file(struct playlist *playlist, const char *path, int uid, ...@@ -87,12 +88,12 @@ playlist_append_file(struct playlist *playlist, const char *path, int uid,
if (song == NULL) if (song == NULL)
return PLAYLIST_RESULT_NO_SUCH_SONG; return PLAYLIST_RESULT_NO_SUCH_SONG;
return playlist_append_song(playlist, song, added_id); return playlist_append_song(playlist, pc, song, added_id);
} }
#endif #endif
enum playlist_result enum playlist_result
playlist_append_song(struct playlist *playlist, playlist_append_song(struct playlist *playlist, struct player_control *pc,
struct song *song, unsigned *added_id) struct song *song, unsigned *added_id)
{ {
const struct song *queued; const struct song *queued;
...@@ -121,7 +122,7 @@ playlist_append_song(struct playlist *playlist, ...@@ -121,7 +122,7 @@ playlist_append_song(struct playlist *playlist,
playlist_increment_version(playlist); playlist_increment_version(playlist);
playlist_update_queued_song(playlist, queued); playlist_update_queued_song(playlist, pc, queued);
if (added_id) if (added_id)
*added_id = id; *added_id = id;
...@@ -145,8 +146,8 @@ song_by_uri(const char *uri) ...@@ -145,8 +146,8 @@ song_by_uri(const char *uri)
} }
enum playlist_result enum playlist_result
playlist_append_uri(struct playlist *playlist, const char *uri, playlist_append_uri(struct playlist *playlist, struct player_control *pc,
unsigned *added_id) const char *uri, unsigned *added_id)
{ {
struct song *song; struct song *song;
...@@ -156,11 +157,12 @@ playlist_append_uri(struct playlist *playlist, const char *uri, ...@@ -156,11 +157,12 @@ playlist_append_uri(struct playlist *playlist, const char *uri,
if (song == NULL) if (song == NULL)
return PLAYLIST_RESULT_NO_SUCH_SONG; return PLAYLIST_RESULT_NO_SUCH_SONG;
return playlist_append_song(playlist, song, added_id); return playlist_append_song(playlist, pc, song, added_id);
} }
enum playlist_result enum playlist_result
playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2) playlist_swap_songs(struct playlist *playlist, struct player_control *pc,
unsigned song1, unsigned song2)
{ {
const struct song *queued; const struct song *queued;
...@@ -192,13 +194,14 @@ playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2) ...@@ -192,13 +194,14 @@ playlist_swap_songs(struct playlist *playlist, unsigned song1, unsigned song2)
playlist_increment_version(playlist); playlist_increment_version(playlist);
playlist_update_queued_song(playlist, queued); playlist_update_queued_song(playlist, pc, queued);
return PLAYLIST_RESULT_SUCCESS; return PLAYLIST_RESULT_SUCCESS;
} }
enum playlist_result enum playlist_result
playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2) playlist_swap_songs_id(struct playlist *playlist, struct player_control *pc,
unsigned id1, unsigned id2)
{ {
int song1 = queue_id_to_position(&playlist->queue, id1); int song1 = queue_id_to_position(&playlist->queue, id1);
int song2 = queue_id_to_position(&playlist->queue, id2); int song2 = queue_id_to_position(&playlist->queue, id2);
...@@ -206,12 +209,12 @@ playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2) ...@@ -206,12 +209,12 @@ playlist_swap_songs_id(struct playlist *playlist, unsigned id1, unsigned id2)
if (song1 < 0 || song2 < 0) if (song1 < 0 || song2 < 0)
return PLAYLIST_RESULT_NO_SUCH_SONG; return PLAYLIST_RESULT_NO_SUCH_SONG;
return playlist_swap_songs(playlist, song1, song2); return playlist_swap_songs(playlist, pc, song1, song2);
} }
static void static void
playlist_delete_internal(struct playlist *playlist, unsigned song, playlist_delete_internal(struct playlist *playlist, struct player_control *pc,
const struct song **queued_p) unsigned song, const struct song **queued_p)
{ {
unsigned songOrder; unsigned songOrder;
...@@ -220,11 +223,11 @@ playlist_delete_internal(struct playlist *playlist, unsigned song, ...@@ -220,11 +223,11 @@ playlist_delete_internal(struct playlist *playlist, unsigned song,
songOrder = queue_position_to_order(&playlist->queue, song); songOrder = queue_position_to_order(&playlist->queue, song);
if (playlist->playing && playlist->current == (int)songOrder) { if (playlist->playing && playlist->current == (int)songOrder) {
bool paused = pc_get_state() == PLAYER_STATE_PAUSE; bool paused = pc_get_state(pc) == PLAYER_STATE_PAUSE;
/* the current song is going to be deleted: stop the player */ /* the current song is going to be deleted: stop the player */
pc_stop(); pc_stop(pc);
playlist->playing = false; playlist->playing = false;
/* see which song is going to be played instead */ /* see which song is going to be played instead */
...@@ -236,11 +239,11 @@ playlist_delete_internal(struct playlist *playlist, unsigned song, ...@@ -236,11 +239,11 @@ playlist_delete_internal(struct playlist *playlist, unsigned song,
if (playlist->current >= 0 && !paused) if (playlist->current >= 0 && !paused)
/* play the song after the deleted one */ /* play the song after the deleted one */
playlist_play_order(playlist, playlist->current); playlist_play_order(playlist, pc, playlist->current);
else else
/* no songs left to play, stop playback /* no songs left to play, stop playback
completely */ completely */
playlist_stop(playlist); playlist_stop(playlist, pc);
*queued_p = NULL; *queued_p = NULL;
} else if (playlist->current == (int)songOrder) } else if (playlist->current == (int)songOrder)
...@@ -251,7 +254,7 @@ playlist_delete_internal(struct playlist *playlist, unsigned song, ...@@ -251,7 +254,7 @@ playlist_delete_internal(struct playlist *playlist, unsigned song,
/* now do it: remove the song */ /* now do it: remove the song */
if (!song_in_database(queue_get(&playlist->queue, song))) if (!song_in_database(queue_get(&playlist->queue, song)))
pc_song_deleted(queue_get(&playlist->queue, song)); pc_song_deleted(pc, queue_get(&playlist->queue, song));
queue_delete(&playlist->queue, song); queue_delete(&playlist->queue, song);
...@@ -263,7 +266,8 @@ playlist_delete_internal(struct playlist *playlist, unsigned song, ...@@ -263,7 +266,8 @@ playlist_delete_internal(struct playlist *playlist, unsigned song,
} }
enum playlist_result enum playlist_result
playlist_delete(struct playlist *playlist, unsigned song) playlist_delete(struct playlist *playlist, struct player_control *pc,
unsigned song)
{ {
const struct song *queued; const struct song *queued;
...@@ -272,16 +276,17 @@ playlist_delete(struct playlist *playlist, unsigned song) ...@@ -272,16 +276,17 @@ playlist_delete(struct playlist *playlist, unsigned song)
queued = playlist_get_queued_song(playlist); queued = playlist_get_queued_song(playlist);
playlist_delete_internal(playlist, song, &queued); playlist_delete_internal(playlist, pc, song, &queued);
playlist_increment_version(playlist); playlist_increment_version(playlist);
playlist_update_queued_song(playlist, queued); playlist_update_queued_song(playlist, pc, queued);
return PLAYLIST_RESULT_SUCCESS; return PLAYLIST_RESULT_SUCCESS;
} }
enum playlist_result enum playlist_result
playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end) playlist_delete_range(struct playlist *playlist, struct player_control *pc,
unsigned start, unsigned end)
{ {
const struct song *queued; const struct song *queued;
...@@ -297,37 +302,39 @@ playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end) ...@@ -297,37 +302,39 @@ playlist_delete_range(struct playlist *playlist, unsigned start, unsigned end)
queued = playlist_get_queued_song(playlist); queued = playlist_get_queued_song(playlist);
do { do {
playlist_delete_internal(playlist, --end, &queued); playlist_delete_internal(playlist, pc, --end, &queued);
} while (end != start); } while (end != start);
playlist_increment_version(playlist); playlist_increment_version(playlist);
playlist_update_queued_song(playlist, queued); playlist_update_queued_song(playlist, pc, queued);
return PLAYLIST_RESULT_SUCCESS; return PLAYLIST_RESULT_SUCCESS;
} }
enum playlist_result enum playlist_result
playlist_delete_id(struct playlist *playlist, unsigned id) playlist_delete_id(struct playlist *playlist, struct player_control *pc,
unsigned id)
{ {
int song = queue_id_to_position(&playlist->queue, id); int song = queue_id_to_position(&playlist->queue, id);
if (song < 0) if (song < 0)
return PLAYLIST_RESULT_NO_SUCH_SONG; return PLAYLIST_RESULT_NO_SUCH_SONG;
return playlist_delete(playlist, song); return playlist_delete(playlist, pc, song);
} }
void void
playlist_delete_song(struct playlist *playlist, const struct song *song) playlist_delete_song(struct playlist *playlist, struct player_control *pc,
const struct song *song)
{ {
for (int i = queue_length(&playlist->queue) - 1; i >= 0; --i) for (int i = queue_length(&playlist->queue) - 1; i >= 0; --i)
if (song == queue_get(&playlist->queue, i)) if (song == queue_get(&playlist->queue, i))
playlist_delete(playlist, i); playlist_delete(playlist, pc, i);
pc_song_deleted(song); pc_song_deleted(pc, song);
} }
enum playlist_result enum playlist_result
playlist_move_range(struct playlist *playlist, playlist_move_range(struct playlist *playlist, struct player_control *pc,
unsigned start, unsigned end, int to) unsigned start, unsigned end, int to)
{ {
const struct song *queued; const struct song *queued;
...@@ -382,23 +389,25 @@ playlist_move_range(struct playlist *playlist, ...@@ -382,23 +389,25 @@ playlist_move_range(struct playlist *playlist,
playlist_increment_version(playlist); playlist_increment_version(playlist);
playlist_update_queued_song(playlist, queued); playlist_update_queued_song(playlist, pc, queued);
return PLAYLIST_RESULT_SUCCESS; return PLAYLIST_RESULT_SUCCESS;
} }
enum playlist_result enum playlist_result
playlist_move_id(struct playlist *playlist, unsigned id1, int to) playlist_move_id(struct playlist *playlist, struct player_control *pc,
unsigned id1, int to)
{ {
int song = queue_id_to_position(&playlist->queue, id1); int song = queue_id_to_position(&playlist->queue, id1);
if (song < 0) if (song < 0)
return PLAYLIST_RESULT_NO_SUCH_SONG; return PLAYLIST_RESULT_NO_SUCH_SONG;
return playlist_move_range(playlist, song, song+1, to); return playlist_move_range(playlist, pc, song, song+1, to);
} }
void void
playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end) playlist_shuffle(struct playlist *playlist, struct player_control *pc,
unsigned start, unsigned end)
{ {
const struct song *queued; const struct song *queued;
...@@ -440,5 +449,5 @@ playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end) ...@@ -440,5 +449,5 @@ playlist_shuffle(struct playlist *playlist, unsigned start, unsigned end)
playlist_increment_version(playlist); playlist_increment_version(playlist);
playlist_update_queued_song(playlist, queued); playlist_update_queued_song(playlist, pc, queued);
} }
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "playlist.h" #include "playlist.h"
#include "playlist_state.h" #include "playlist_state.h"
#include "event_pipe.h" #include "event_pipe.h"
#include "main.h"
struct playlist g_playlist; struct playlist g_playlist;
...@@ -38,7 +39,7 @@ playlist_tag_event(void) ...@@ -38,7 +39,7 @@ playlist_tag_event(void)
static void static void
playlist_event(void) playlist_event(void)
{ {
playlist_sync(&g_playlist); playlist_sync(&g_playlist, global_player_control);
} }
void void
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include "playlist.h" #include "playlist.h"
struct player_control;
/** /**
* Returns the song object which is currently queued. Returns none if * Returns the song object which is currently queued. Returns none if
* there is none (yet?) or if MPD isn't playing. * there is none (yet?) or if MPD isn't playing.
...@@ -44,9 +46,11 @@ playlist_get_queued_song(struct playlist *playlist); ...@@ -44,9 +46,11 @@ playlist_get_queued_song(struct playlist *playlist);
*/ */
void void
playlist_update_queued_song(struct playlist *playlist, playlist_update_queued_song(struct playlist *playlist,
struct player_control *pc,
const struct song *prev); const struct song *prev);
void void
playlist_play_order(struct playlist *playlist, int orderNum); playlist_play_order(struct playlist *playlist, struct player_control *pc,
int orderNum);
#endif #endif
...@@ -27,7 +27,8 @@ ...@@ -27,7 +27,8 @@
enum playlist_result enum playlist_result
playlist_load_into_queue(const char *uri, struct playlist_provider *source, playlist_load_into_queue(const char *uri, struct playlist_provider *source,
struct playlist *dest, bool secure) struct playlist *dest, struct player_control *pc,
bool secure)
{ {
enum playlist_result result; enum playlist_result result;
struct song *song; struct song *song;
...@@ -38,7 +39,7 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source, ...@@ -38,7 +39,7 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source,
if (song == NULL) if (song == NULL)
continue; continue;
result = playlist_append_song(dest, song, NULL); result = playlist_append_song(dest, pc, song, NULL);
if (result != PLAYLIST_RESULT_SUCCESS) { if (result != PLAYLIST_RESULT_SUCCESS) {
if (!song_in_database(song)) if (!song_in_database(song))
song_free(song); song_free(song);
...@@ -53,7 +54,9 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source, ...@@ -53,7 +54,9 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source,
} }
enum playlist_result enum playlist_result
playlist_open_into_queue(const char *uri, struct playlist *dest, bool secure) playlist_open_into_queue(const char *uri,
struct playlist *dest, struct player_control *pc,
bool secure)
{ {
struct input_stream *is; struct input_stream *is;
struct playlist_provider *playlist = playlist_open_any(uri, &is); struct playlist_provider *playlist = playlist_open_any(uri, &is);
...@@ -61,7 +64,7 @@ playlist_open_into_queue(const char *uri, struct playlist *dest, bool secure) ...@@ -61,7 +64,7 @@ playlist_open_into_queue(const char *uri, struct playlist *dest, bool secure)
return PLAYLIST_RESULT_NO_SUCH_LIST; return PLAYLIST_RESULT_NO_SUCH_LIST;
enum playlist_result result = enum playlist_result result =
playlist_load_into_queue(uri, playlist, dest, secure); playlist_load_into_queue(uri, playlist, dest, pc, secure);
playlist_plugin_close(playlist); playlist_plugin_close(playlist);
if (is != NULL) if (is != NULL)
......
...@@ -40,14 +40,17 @@ struct playlist; ...@@ -40,14 +40,17 @@ struct playlist;
*/ */
enum playlist_result enum playlist_result
playlist_load_into_queue(const char *uri, struct playlist_provider *source, playlist_load_into_queue(const char *uri, struct playlist_provider *source,
struct playlist *dest, bool secure); struct playlist *dest, struct player_control *pc,
bool secure);
/** /**
* Opens a playlist with a playlist plugin and append to the specified * Opens a playlist with a playlist plugin and append to the specified
* play queue. * play queue.
*/ */
enum playlist_result enum playlist_result
playlist_open_into_queue(const char *uri, struct playlist *dest, bool secure); playlist_open_into_queue(const char *uri,
struct playlist *dest, struct player_control *pc,
bool secure);
#endif #endif
...@@ -109,7 +109,8 @@ spl_save_playlist(const char *name_utf8, const struct playlist *playlist) ...@@ -109,7 +109,8 @@ spl_save_playlist(const char *name_utf8, const struct playlist *playlist)
} }
enum playlist_result enum playlist_result
playlist_load_spl(struct playlist *playlist, const char *name_utf8) playlist_load_spl(struct playlist *playlist, struct player_control *pc,
const char *name_utf8)
{ {
GPtrArray *list; GPtrArray *list;
...@@ -119,7 +120,7 @@ playlist_load_spl(struct playlist *playlist, const char *name_utf8) ...@@ -119,7 +120,7 @@ playlist_load_spl(struct playlist *playlist, const char *name_utf8)
for (unsigned i = 0; i < list->len; ++i) { for (unsigned i = 0; i < list->len; ++i) {
const char *temp = g_ptr_array_index(list, i); const char *temp = g_ptr_array_index(list, i);
if ((playlist_append_uri(playlist, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) { if ((playlist_append_uri(playlist, pc, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
/* for windows compatibility, convert slashes */ /* for windows compatibility, convert slashes */
char *temp2 = g_strdup(temp); char *temp2 = g_strdup(temp);
char *p = temp2; char *p = temp2;
...@@ -128,7 +129,7 @@ playlist_load_spl(struct playlist *playlist, const char *name_utf8) ...@@ -128,7 +129,7 @@ playlist_load_spl(struct playlist *playlist, const char *name_utf8)
*p = '/'; *p = '/';
p++; p++;
} }
if ((playlist_append_uri(playlist, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) { if ((playlist_append_uri(playlist, pc, temp, NULL)) != PLAYLIST_RESULT_SUCCESS) {
g_warning("can't add file \"%s\"", temp2); g_warning("can't add file \"%s\"", temp2);
} }
g_free(temp2); g_free(temp2);
......
...@@ -49,6 +49,7 @@ spl_save_playlist(const char *name_utf8, const struct playlist *playlist); ...@@ -49,6 +49,7 @@ spl_save_playlist(const char *name_utf8, const struct playlist *playlist);
* playlist. * playlist.
*/ */
enum playlist_result enum playlist_result
playlist_load_spl(struct playlist *playlist, const char *name_utf8); playlist_load_spl(struct playlist *playlist, struct player_control *pc,
const char *name_utf8);
#endif #endif
...@@ -53,11 +53,12 @@ ...@@ -53,11 +53,12 @@
#define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX #define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX
void void
playlist_state_save(FILE *fp, const struct playlist *playlist) playlist_state_save(FILE *fp, const struct playlist *playlist,
struct player_control *pc)
{ {
struct player_status player_status; struct player_status player_status;
pc_get_status(&player_status); pc_get_status(pc, &player_status);
fputs(PLAYLIST_STATE_FILE_STATE, fp); fputs(PLAYLIST_STATE_FILE_STATE, fp);
...@@ -89,10 +90,11 @@ playlist_state_save(FILE *fp, const struct playlist *playlist) ...@@ -89,10 +90,11 @@ playlist_state_save(FILE *fp, const struct playlist *playlist)
fprintf(fp, PLAYLIST_STATE_FILE_CONSUME "%i\n", fprintf(fp, PLAYLIST_STATE_FILE_CONSUME "%i\n",
playlist->queue.consume); playlist->queue.consume);
fprintf(fp, PLAYLIST_STATE_FILE_CROSSFADE "%i\n", fprintf(fp, PLAYLIST_STATE_FILE_CROSSFADE "%i\n",
(int)(pc_get_cross_fade())); (int)(pc_get_cross_fade(pc)));
fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n", pc_get_mixramp_db()); fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n",
pc_get_mixramp_db(pc));
fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDELAY "%f\n", fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDELAY "%f\n",
pc_get_mixramp_delay()); pc_get_mixramp_delay(pc));
fputs(PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "\n", fp); fputs(PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "\n", fp);
queue_save(fp, &playlist->queue); queue_save(fp, &playlist->queue);
fputs(PLAYLIST_STATE_FILE_PLAYLIST_END "\n", fp); fputs(PLAYLIST_STATE_FILE_PLAYLIST_END "\n", fp);
...@@ -123,7 +125,7 @@ playlist_state_load(FILE *fp, GString *buffer, struct playlist *playlist) ...@@ -123,7 +125,7 @@ playlist_state_load(FILE *fp, GString *buffer, struct playlist *playlist)
bool bool
playlist_state_restore(const char *line, FILE *fp, GString *buffer, playlist_state_restore(const char *line, FILE *fp, GString *buffer,
struct playlist *playlist) struct playlist *playlist, struct player_control *pc)
{ {
int current = -1; int current = -1;
int seek_time = 0; int seek_time = 0;
...@@ -148,16 +150,16 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer, ...@@ -148,16 +150,16 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer,
if (strcmp if (strcmp
(&(line[strlen(PLAYLIST_STATE_FILE_REPEAT)]), (&(line[strlen(PLAYLIST_STATE_FILE_REPEAT)]),
"1") == 0) { "1") == 0) {
playlist_set_repeat(playlist, true); playlist_set_repeat(playlist, pc, true);
} else } else
playlist_set_repeat(playlist, false); playlist_set_repeat(playlist, pc, false);
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_SINGLE)) { } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_SINGLE)) {
if (strcmp if (strcmp
(&(line[strlen(PLAYLIST_STATE_FILE_SINGLE)]), (&(line[strlen(PLAYLIST_STATE_FILE_SINGLE)]),
"1") == 0) { "1") == 0) {
playlist_set_single(playlist, true); playlist_set_single(playlist, pc, true);
} else } else
playlist_set_single(playlist, false); playlist_set_single(playlist, pc, false);
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CONSUME)) { } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CONSUME)) {
if (strcmp if (strcmp
(&(line[strlen(PLAYLIST_STATE_FILE_CONSUME)]), (&(line[strlen(PLAYLIST_STATE_FILE_CONSUME)]),
...@@ -166,11 +168,14 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer, ...@@ -166,11 +168,14 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer,
} else } else
playlist_set_consume(playlist, false); playlist_set_consume(playlist, false);
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CROSSFADE)) { } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CROSSFADE)) {
pc_set_cross_fade(atoi(line + strlen(PLAYLIST_STATE_FILE_CROSSFADE))); pc_set_cross_fade(pc,
atoi(line + strlen(PLAYLIST_STATE_FILE_CROSSFADE)));
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDB)) { } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDB)) {
pc_set_mixramp_db(atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDB))); pc_set_mixramp_db(pc,
atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDB)));
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDELAY)) { } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDELAY)) {
pc_set_mixramp_delay(atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDELAY))); pc_set_mixramp_delay(pc,
atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDELAY)));
} else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_RANDOM)) { } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_RANDOM)) {
random_mode = random_mode =
strcmp(line + strlen(PLAYLIST_STATE_FILE_RANDOM), strcmp(line + strlen(PLAYLIST_STATE_FILE_RANDOM),
...@@ -185,7 +190,7 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer, ...@@ -185,7 +190,7 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer,
} }
} }
playlist_set_random(playlist, random_mode); playlist_set_random(playlist, pc, random_mode);
if (!queue_is_empty(&playlist->queue)) { if (!queue_is_empty(&playlist->queue)) {
if (!queue_valid_position(&playlist->queue, current)) if (!queue_valid_position(&playlist->queue, current))
...@@ -195,28 +200,29 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer, ...@@ -195,28 +200,29 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer,
called here, after the audio output states were called here, after the audio output states were
restored, before playback begins */ restored, before playback begins */
if (state != PLAYER_STATE_STOP) if (state != PLAYER_STATE_STOP)
pc_update_audio(); pc_update_audio(pc);
if (state == PLAYER_STATE_STOP /* && config_option */) if (state == PLAYER_STATE_STOP /* && config_option */)
playlist->current = current; playlist->current = current;
else if (seek_time == 0) else if (seek_time == 0)
playlist_play(playlist, current); playlist_play(playlist, pc, current);
else else
playlist_seek_song(playlist, current, seek_time); playlist_seek_song(playlist, pc, current, seek_time);
if (state == PLAYER_STATE_PAUSE) if (state == PLAYER_STATE_PAUSE)
pc_pause(); pc_pause(pc);
} }
return true; return true;
} }
unsigned unsigned
playlist_state_get_hash(const struct playlist *playlist) playlist_state_get_hash(const struct playlist *playlist,
struct player_control *pc)
{ {
struct player_status player_status; struct player_status player_status;
pc_get_status(&player_status); pc_get_status(pc, &player_status);
return playlist->queue.version ^ return playlist->queue.version ^
(player_status.state != PLAYER_STATE_STOP (player_status.state != PLAYER_STATE_STOP
...@@ -226,7 +232,7 @@ playlist_state_get_hash(const struct playlist *playlist) ...@@ -226,7 +232,7 @@ playlist_state_get_hash(const struct playlist *playlist)
? (queue_order_to_position(&playlist->queue, ? (queue_order_to_position(&playlist->queue,
playlist->current) << 16) playlist->current) << 16)
: 0) ^ : 0) ^
((int)pc_get_cross_fade() << 20) ^ ((int)pc_get_cross_fade(pc) << 20) ^
(player_status.state << 24) ^ (player_status.state << 24) ^
(playlist->queue.random << 27) ^ (playlist->queue.random << 27) ^
(playlist->queue.repeat << 28) ^ (playlist->queue.repeat << 28) ^
......
...@@ -30,13 +30,15 @@ ...@@ -30,13 +30,15 @@
#include <stdio.h> #include <stdio.h>
struct playlist; struct playlist;
struct player_control;
void void
playlist_state_save(FILE *fp, const struct playlist *playlist); playlist_state_save(FILE *fp, const struct playlist *playlist,
struct player_control *pc);
bool bool
playlist_state_restore(const char *line, FILE *fp, GString *buffer, playlist_state_restore(const char *line, FILE *fp, GString *buffer,
struct playlist *playlist); struct playlist *playlist, struct player_control *pc);
/** /**
* Generates a hash number for the current state of the playlist and * Generates a hash number for the current state of the playlist and
...@@ -45,6 +47,7 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer, ...@@ -45,6 +47,7 @@ playlist_state_restore(const char *line, FILE *fp, GString *buffer,
* be saved. * be saved.
*/ */
unsigned unsigned
playlist_state_get_hash(const struct playlist *playlist); playlist_state_get_hash(const struct playlist *playlist,
struct player_control *pc);
#endif #endif
...@@ -47,7 +47,7 @@ static unsigned prev_volume_version, prev_output_version, ...@@ -47,7 +47,7 @@ static unsigned prev_volume_version, prev_output_version,
prev_playlist_version; prev_playlist_version;
static void static void
state_file_write(void) state_file_write(struct player_control *pc)
{ {
FILE *fp; FILE *fp;
...@@ -64,17 +64,17 @@ state_file_write(void) ...@@ -64,17 +64,17 @@ state_file_write(void)
save_sw_volume_state(fp); save_sw_volume_state(fp);
audio_output_state_save(fp); audio_output_state_save(fp);
playlist_state_save(fp, &g_playlist); playlist_state_save(fp, &g_playlist, pc);
fclose(fp); fclose(fp);
prev_volume_version = sw_volume_state_get_hash(); prev_volume_version = sw_volume_state_get_hash();
prev_output_version = audio_output_state_get_version(); prev_output_version = audio_output_state_get_version();
prev_playlist_version = playlist_state_get_hash(&g_playlist); prev_playlist_version = playlist_state_get_hash(&g_playlist, pc);
} }
static void static void
state_file_read(void) state_file_read(struct player_control *pc)
{ {
FILE *fp; FILE *fp;
bool success; bool success;
...@@ -95,7 +95,8 @@ state_file_read(void) ...@@ -95,7 +95,8 @@ state_file_read(void)
while ((line = read_text_line(fp, buffer)) != NULL) { while ((line = read_text_line(fp, buffer)) != NULL) {
success = read_sw_volume_state(line) || success = read_sw_volume_state(line) ||
audio_output_state_read(line) || audio_output_state_read(line) ||
playlist_state_restore(line, fp, buffer, &g_playlist); playlist_state_restore(line, fp, buffer,
&g_playlist, pc);
if (!success) if (!success)
g_warning("Unrecognized line in state file: %s", line); g_warning("Unrecognized line in state file: %s", line);
} }
...@@ -104,7 +105,7 @@ state_file_read(void) ...@@ -104,7 +105,7 @@ state_file_read(void)
prev_volume_version = sw_volume_state_get_hash(); prev_volume_version = sw_volume_state_get_hash();
prev_output_version = audio_output_state_get_version(); prev_output_version = audio_output_state_get_version();
prev_playlist_version = playlist_state_get_hash(&g_playlist); prev_playlist_version = playlist_state_get_hash(&g_playlist, pc);
g_string_free(buffer, true); g_string_free(buffer, true);
...@@ -115,21 +116,23 @@ state_file_read(void) ...@@ -115,21 +116,23 @@ state_file_read(void)
* saves the state file. * saves the state file.
*/ */
static gboolean static gboolean
timer_save_state_file(G_GNUC_UNUSED gpointer data) timer_save_state_file(gpointer data)
{ {
struct player_control *pc = data;
if (prev_volume_version == sw_volume_state_get_hash() && if (prev_volume_version == sw_volume_state_get_hash() &&
prev_output_version == audio_output_state_get_version() && prev_output_version == audio_output_state_get_version() &&
prev_playlist_version == playlist_state_get_hash(&g_playlist)) prev_playlist_version == playlist_state_get_hash(&g_playlist, pc))
/* nothing has changed - don't save the state file, /* nothing has changed - don't save the state file,
don't spin up the hard disk */ don't spin up the hard disk */
return true; return true;
state_file_write(); state_file_write(pc);
return true; return true;
} }
void void
state_file_init(const char *path) state_file_init(const char *path, struct player_control *pc)
{ {
assert(state_file_path == NULL); assert(state_file_path == NULL);
...@@ -137,15 +140,15 @@ state_file_init(const char *path) ...@@ -137,15 +140,15 @@ state_file_init(const char *path)
return; return;
state_file_path = g_strdup(path); state_file_path = g_strdup(path);
state_file_read(); state_file_read(pc);
save_state_source_id = g_timeout_add_seconds(5 * 60, save_state_source_id = g_timeout_add_seconds(5 * 60,
timer_save_state_file, timer_save_state_file,
NULL); pc);
} }
void void
state_file_finish(void) state_file_finish(struct player_control *pc)
{ {
if (state_file_path == NULL) if (state_file_path == NULL)
/* no state file configured, no cleanup required */ /* no state file configured, no cleanup required */
...@@ -154,7 +157,7 @@ state_file_finish(void) ...@@ -154,7 +157,7 @@ state_file_finish(void)
if (save_state_source_id != 0) if (save_state_source_id != 0)
g_source_remove(save_state_source_id); g_source_remove(save_state_source_id);
state_file_write(); state_file_write(pc);
g_free(state_file_path); g_free(state_file_path);
} }
...@@ -20,11 +20,13 @@ ...@@ -20,11 +20,13 @@
#ifndef MPD_STATE_FILE_H #ifndef MPD_STATE_FILE_H
#define MPD_STATE_FILE_H #define MPD_STATE_FILE_H
struct player_control;
void void
state_file_init(const char *path); state_file_init(const char *path, struct player_control *pc);
void void
state_file_finish(void); state_file_finish(struct player_control *pc);
void write_state_file(void); void write_state_file(void);
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "client.h" #include "client.h"
#include "player_control.h" #include "player_control.h"
#include "strset.h" #include "strset.h"
#include "client_internal.h"
struct stats stats; struct stats stats;
...@@ -114,7 +115,7 @@ int stats_print(struct client *client) ...@@ -114,7 +115,7 @@ int stats_print(struct client *client)
stats.album_count, stats.album_count,
stats.song_count, stats.song_count,
(long)g_timer_elapsed(stats.timer, NULL), (long)g_timer_elapsed(stats.timer, NULL),
(long)(pc_get_total_play_time() + 0.5), (long)(pc_get_total_play_time(client->player_control) + 0.5),
stats.song_duration, stats.song_duration,
db_get_mtime()); db_get_mtime());
return 0; return 0;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "event_pipe.h" #include "event_pipe.h"
#include "song.h" #include "song.h"
#include "playlist.h" #include "playlist.h"
#include "main.h"
#ifdef ENABLE_SQLITE #ifdef ENABLE_SQLITE
#include "sticker.h" #include "sticker.h"
...@@ -58,7 +59,7 @@ song_remove_event(void) ...@@ -58,7 +59,7 @@ song_remove_event(void)
sticker_song_delete(removed_song); sticker_song_delete(removed_song);
#endif #endif
playlist_delete_song(&g_playlist, removed_song); playlist_delete_song(&g_playlist, global_player_control, removed_song);
removed_song = NULL; removed_song = NULL;
notify_signal(&remove_notify); notify_signal(&remove_notify);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "event_pipe.h" #include "event_pipe.h"
#include "idle.h" #include "idle.h"
#include "playlist.h" #include "playlist.h"
#include "player_control.h"
#include "stdbin.h" #include "stdbin.h"
#include <glib.h> #include <glib.h>
...@@ -104,7 +105,9 @@ load_audio_output(struct audio_output *ao, const char *name) ...@@ -104,7 +105,9 @@ load_audio_output(struct audio_output *ao, const char *name)
return false; return false;
} }
success = audio_output_init(ao, param, &error); static struct player_control dummy_player_control;
success = audio_output_init(ao, param, &dummy_player_control, &error);
if (!success) { if (!success) {
g_printerr("%s\n", error->message); g_printerr("%s\n", error->message);
g_error_free(error); g_error_free(error);
......
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