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