diff options
42 files changed, 742 insertions, 572 deletions
diff --git a/src/client.h b/src/client.h index d46747b4f..73e744520 100644 --- a/src/client.h +++ b/src/client.h @@ -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); diff --git a/src/client_internal.h b/src/client_internal.h index 2b1b92433..1518065e0 100644 --- a/src/client_internal.h +++ b/src/client_internal.h @@ -32,6 +32,8 @@ struct deferred_buffer { }; struct client { + struct player_control *player_control; + GIOChannel *channel; guint source_id; diff --git a/src/client_new.c b/src/client_new.c index 781a36524..5613656c0 100644 --- a/src/client_new.c +++ b/src/client_new.c @@ -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); diff --git a/src/command.c b/src/command.c index ccdaf264a..acbc7eb85 100644 --- a/src/command.c +++ b/src/command.c @@ -44,6 +44,7 @@ #include "dbUtils.h" #include "tag.h" #include "client.h" +#include "client_internal.h" #include "tag_print.h" #include "path.h" #include "replay_gain_config.h" @@ -434,7 +435,7 @@ handle_play(struct client *client, int argc, char *argv[]) if (argc == 2 && !check_int(client, &song, argv[1], need_positive)) return COMMAND_RETURN_ERROR; - result = playlist_play(&g_playlist, song); + result = playlist_play(&g_playlist, client->player_control, song); return print_playlist_result(client, result); } @@ -447,7 +448,7 @@ handle_playid(struct client *client, int argc, char *argv[]) if (argc == 2 && !check_int(client, &id, argv[1], need_positive)) return COMMAND_RETURN_ERROR; - result = playlist_play_id(&g_playlist, id); + result = playlist_play_id(&g_playlist, client->player_control, id); return print_playlist_result(client, result); } @@ -455,7 +456,7 @@ static enum command_return handle_stop(G_GNUC_UNUSED struct client *client, G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) { - playlist_stop(&g_playlist); + playlist_stop(&g_playlist, client->player_control); return COMMAND_RETURN_OK; } @@ -476,9 +477,9 @@ handle_pause(struct client *client, if (!check_bool(client, &pause_flag, argv[1])) return COMMAND_RETURN_ERROR; - pc_set_pause(pause_flag); + pc_set_pause(client->player_control, pause_flag); } else - pc_pause(); + pc_pause(client->player_control); return COMMAND_RETURN_OK; } @@ -493,7 +494,7 @@ handle_status(struct client *client, char *error; int song; - pc_get_status(&player_status); + pc_get_status(client->player_control, &player_status); switch (player_status.state) { case PLAYER_STATE_STOP: @@ -526,9 +527,9 @@ handle_status(struct client *client, playlist_get_consume(&g_playlist), playlist_get_version(&g_playlist), playlist_get_length(&g_playlist), - (int)(pc_get_cross_fade() + 0.5), - pc_get_mixramp_db(), - pc_get_mixramp_delay(), + (int)(pc_get_cross_fade(client->player_control) + 0.5), + pc_get_mixramp_db(client->player_control), + pc_get_mixramp_delay(client->player_control), state); song = playlist_get_current_song(&g_playlist); @@ -561,7 +562,7 @@ handle_status(struct client *client, updateJobId); } - error = pc_get_error_message(); + error = pc_get_error_message(client->player_control); if (error != NULL) { client_printf(client, COMMAND_STATUS_ERROR ": %s\n", @@ -605,6 +606,7 @@ handle_add(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) result = PLAYLIST_RESULT_DENIED; #else result = playlist_append_file(&g_playlist, + client->player_control, uri + 7, client_get_uid(client), NULL); #endif @@ -618,11 +620,13 @@ handle_add(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) return COMMAND_RETURN_ERROR; } - result = playlist_append_uri(&g_playlist, uri, NULL); + result = playlist_append_uri(&g_playlist, + client->player_control, + uri, NULL); return print_playlist_result(client, result); } - result = addAllIn(uri); + result = addAllIn(client->player_control, uri); if (result == (enum playlist_result)-1) { command_error(client, ACK_ERROR_NO_EXIST, "directory or file not found"); @@ -643,7 +647,9 @@ handle_addid(struct client *client, int argc, char *argv[]) #ifdef WIN32 result = PLAYLIST_RESULT_DENIED; #else - result = playlist_append_file(&g_playlist, uri + 7, + result = playlist_append_file(&g_playlist, + client->player_control, + uri + 7, client_get_uid(client), &added_id); #endif @@ -654,7 +660,9 @@ handle_addid(struct client *client, int argc, char *argv[]) return COMMAND_RETURN_ERROR; } - result = playlist_append_uri(&g_playlist, uri, &added_id); + result = playlist_append_uri(&g_playlist, + client->player_control, + uri, &added_id); } if (result != PLAYLIST_RESULT_SUCCESS) @@ -664,11 +672,13 @@ handle_addid(struct client *client, int argc, char *argv[]) int to; if (!check_int(client, &to, argv[2], check_integer, argv[2])) return COMMAND_RETURN_ERROR; - result = playlist_move_id(&g_playlist, added_id, to); + result = playlist_move_id(&g_playlist, client->player_control, + added_id, to); if (result != PLAYLIST_RESULT_SUCCESS) { enum command_return ret = print_playlist_result(client, result); - playlist_delete_id(&g_playlist, added_id); + playlist_delete_id(&g_playlist, client->player_control, + added_id); return ret; } } @@ -686,7 +696,8 @@ handle_delete(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) if (!check_range(client, &start, &end, argv[1], need_range)) return COMMAND_RETURN_ERROR; - result = playlist_delete_range(&g_playlist, start, end); + result = playlist_delete_range(&g_playlist, client->player_control, + start, end); return print_playlist_result(client, result); } @@ -699,7 +710,7 @@ handle_deleteid(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) if (!check_int(client, &id, argv[1], need_positive)) return COMMAND_RETURN_ERROR; - result = playlist_delete_id(&g_playlist, id); + result = playlist_delete_id(&g_playlist, client->player_control, id); return print_playlist_result(client, result); } @@ -720,7 +731,7 @@ handle_shuffle(G_GNUC_UNUSED struct client *client, argv[1], need_range)) return COMMAND_RETURN_ERROR; - playlist_shuffle(&g_playlist, start, end); + playlist_shuffle(&g_playlist, client->player_control, start, end); return COMMAND_RETURN_OK; } @@ -728,7 +739,7 @@ static enum command_return handle_clear(G_GNUC_UNUSED struct client *client, G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) { - playlist_clear(&g_playlist); + playlist_clear(&g_playlist, client->player_control); return COMMAND_RETURN_OK; } @@ -747,11 +758,13 @@ handle_load(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) { enum playlist_result result; - result = playlist_open_into_queue(argv[1], &g_playlist, true); + result = playlist_open_into_queue(argv[1], &g_playlist, + client->player_control, true); if (result != PLAYLIST_RESULT_NO_SUCH_LIST) return result; - result = playlist_load_spl(&g_playlist, argv[1]); + result = playlist_load_spl(&g_playlist, client->player_control, + argv[1]); return print_playlist_result(client, result); } @@ -1141,7 +1154,7 @@ handle_next(G_GNUC_UNUSED struct client *client, int single = g_playlist.queue.single; g_playlist.queue.single = false; - playlist_next(&g_playlist); + playlist_next(&g_playlist, client->player_control); g_playlist.queue.single = single; return COMMAND_RETURN_OK; @@ -1151,7 +1164,7 @@ static enum command_return handle_previous(G_GNUC_UNUSED struct client *client, G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) { - playlist_previous(&g_playlist); + playlist_previous(&g_playlist, client->player_control); return COMMAND_RETURN_OK; } @@ -1210,7 +1223,7 @@ handle_repeat(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) return COMMAND_RETURN_ERROR; } - playlist_set_repeat(&g_playlist, status); + playlist_set_repeat(&g_playlist, client->player_control, status); return COMMAND_RETURN_OK; } @@ -1228,7 +1241,7 @@ handle_single(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) return COMMAND_RETURN_ERROR; } - playlist_set_single(&g_playlist, status); + playlist_set_single(&g_playlist, client->player_control, status); return COMMAND_RETURN_OK; } @@ -1264,7 +1277,7 @@ handle_random(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) return COMMAND_RETURN_ERROR; } - playlist_set_random(&g_playlist, status); + playlist_set_random(&g_playlist, client->player_control, status); return COMMAND_RETURN_OK; } @@ -1279,7 +1292,7 @@ static enum command_return handle_clearerror(G_GNUC_UNUSED struct client *client, G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) { - pc_clear_error(); + pc_clear_error(client->player_control); return COMMAND_RETURN_OK; } @@ -1348,7 +1361,8 @@ handle_move(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) return COMMAND_RETURN_ERROR; if (!check_int(client, &to, argv[2], check_integer, argv[2])) return COMMAND_RETURN_ERROR; - result = playlist_move_range(&g_playlist, start, end, to); + result = playlist_move_range(&g_playlist, client->player_control, + start, end, to); return print_playlist_result(client, result); } @@ -1362,7 +1376,8 @@ handle_moveid(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) return COMMAND_RETURN_ERROR; if (!check_int(client, &to, argv[2], check_integer, argv[2])) return COMMAND_RETURN_ERROR; - result = playlist_move_id(&g_playlist, id, to); + result = playlist_move_id(&g_playlist, client->player_control, + id, to); return print_playlist_result(client, result); } @@ -1376,7 +1391,8 @@ handle_swap(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) return COMMAND_RETURN_ERROR; if (!check_int(client, &song2, argv[2], check_integer, argv[2])) return COMMAND_RETURN_ERROR; - result = playlist_swap_songs(&g_playlist, song1, song2); + result = playlist_swap_songs(&g_playlist, client->player_control, + song1, song2); return print_playlist_result(client, result); } @@ -1390,7 +1406,8 @@ handle_swapid(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) return COMMAND_RETURN_ERROR; if (!check_int(client, &id2, argv[2], check_integer, argv[2])) return COMMAND_RETURN_ERROR; - result = playlist_swap_songs_id(&g_playlist, id1, id2); + result = playlist_swap_songs_id(&g_playlist, client->player_control, + id1, id2); return print_playlist_result(client, result); } @@ -1405,7 +1422,8 @@ handle_seek(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) if (!check_int(client, &seek_time, argv[2], check_integer, argv[2])) return COMMAND_RETURN_ERROR; - result = playlist_seek_song(&g_playlist, song, seek_time); + result = playlist_seek_song(&g_playlist, client->player_control, + song, seek_time); return print_playlist_result(client, result); } @@ -1420,7 +1438,8 @@ handle_seekid(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) if (!check_int(client, &seek_time, argv[2], check_integer, argv[2])) return COMMAND_RETURN_ERROR; - result = playlist_seek_song_id(&g_playlist, id, seek_time); + result = playlist_seek_song_id(&g_playlist, client->player_control, + id, seek_time); return print_playlist_result(client, result); } @@ -1470,7 +1489,7 @@ handle_crossfade(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) if (!check_unsigned(client, &xfade_time, argv[1])) return COMMAND_RETURN_ERROR; - pc_set_cross_fade(xfade_time); + pc_set_cross_fade(client->player_control, xfade_time); return COMMAND_RETURN_OK; } @@ -1482,7 +1501,7 @@ handle_mixrampdb(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) if (!check_float(client, &db, argv[1])) return COMMAND_RETURN_ERROR; - pc_set_mixramp_db(db); + pc_set_mixramp_db(client->player_control, db); return COMMAND_RETURN_OK; } @@ -1494,7 +1513,7 @@ handle_mixrampdelay(struct client *client, G_GNUC_UNUSED int argc, char *argv[]) if (!check_float(client, &delay_secs, argv[1])) return COMMAND_RETURN_ERROR; - pc_set_mixramp_delay(delay_secs); + pc_set_mixramp_delay(client->player_control, delay_secs); return COMMAND_RETURN_OK; } diff --git a/src/dbUtils.c b/src/dbUtils.c index 888e757a5..e9405093f 100644 --- a/src/dbUtils.c +++ b/src/dbUtils.c @@ -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; } diff --git a/src/dbUtils.h b/src/dbUtils.h index bba253154..89308242a 100644 --- a/src/dbUtils.h +++ b/src/dbUtils.h @@ -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); diff --git a/src/decoder_api.c b/src/decoder_api.c index fe34ea34a..ccfbd3df6 100644 --- a/src/decoder_api.c +++ b/src/decoder_api.c @@ -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; diff --git a/src/decoder_control.c b/src/decoder_control.c index a5e6e4ad3..6cc2849c5 100644 --- a/src/decoder_control.c +++ b/src/decoder_control.c @@ -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 diff --git a/src/decoder_control.h b/src/decoder_control.h index 449e974b7..fafc6dea3 100644 --- a/src/decoder_control.h +++ b/src/decoder_control.h @@ -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); diff --git a/src/decoder_internal.c b/src/decoder_internal.c index 990d728e9..a4aadd4f0 100644 --- a/src/decoder_internal.c +++ b/src/decoder_internal.c @@ -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; } diff --git a/src/decoder_thread.c b/src/decoder_thread.c index 10a796967..a3af62376 100644 --- a/src/decoder_thread.c +++ b/src/decoder_thread.c @@ -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: diff --git a/src/listen.c b/src/listen.c index da2e79909..ee139d47f 100644 --- a/src/listen.c +++ b/src/listen.c @@ -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 diff --git a/src/main.c b/src/main.c index a500e2934..6f5009c43 100644 --- a/src/main.c +++ b/src/main.c @@ -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(); diff --git a/src/main.h b/src/main.h index 9b9cba018..bd6ec05b6 100644 --- a/src/main.h +++ b/src/main.h @@ -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() diff --git a/src/output_all.c b/src/output_all.c index 19c0f0166..8dce9192b 100644 --- a/src/output_all.c +++ b/src/output_all.c @@ -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; } diff --git a/src/output_all.h b/src/output_all.h index a579bf5f1..8861d0149 100644 --- a/src/output_all.h +++ b/src/output_all.h @@ -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 diff --git a/src/output_command.c b/src/output_command.c index 825884e8e..09733cc2f 100644 --- a/src/output_command.c +++ b/src/output_command.c @@ -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; diff --git a/src/output_control.h b/src/output_control.h index 7f4f4a53c..a6477d008 100644 --- a/src/output_control.h +++ b/src/output_control.h @@ -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); /** diff --git a/src/output_init.c b/src/output_init.c index f4700dfb2..0f02344fb 100644 --- a/src/output_init.c +++ b/src/output_init.c @@ -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, diff --git a/src/output_internal.h b/src/output_internal.h index 18d431352..a548b8c01 100644 --- a/src/output_internal.h +++ b/src/output_internal.h @@ -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 diff --git a/src/output_thread.c b/src/output_thread.c index a5244c693..3e1cd4a25 100644 --- a/src/output_thread.c +++ b/src/output_thread.c @@ -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; diff --git a/src/player_control.c b/src/player_control.c index a190bbd8b..049fc0d1f 100644 --- a/src/player_control.c +++ b/src/player_control.c @@ -32,237 +32,247 @@ #include <stdio.h> #include <math.h> -struct player_control pc; - static void -pc_enqueue_song_locked(struct song *song); +pc_enqueue_song_locked(struct player_control *pc, struct song *song); -void pc_init(unsigned buffer_chunks, unsigned int buffered_before_play) +struct player_control * +pc_new(unsigned buffer_chunks, unsigned int buffered_before_play) { - pc.buffer_chunks = buffer_chunks; - pc.buffered_before_play = buffered_before_play; - - pc.mutex = g_mutex_new(); - pc.cond = g_cond_new(); - - pc.command = PLAYER_COMMAND_NONE; - pc.error = PLAYER_ERROR_NOERROR; - pc.state = PLAYER_STATE_STOP; - pc.cross_fade_seconds = 0; - pc.mixramp_db = 0; - pc.mixramp_delay_seconds = nanf(""); + struct player_control *pc = g_new0(struct player_control, 1); + + pc->buffer_chunks = buffer_chunks; + pc->buffered_before_play = buffered_before_play; + + pc->mutex = g_mutex_new(); + pc->cond = g_cond_new(); + + pc->command = PLAYER_COMMAND_NONE; + pc->error = PLAYER_ERROR_NOERROR; + pc->state = PLAYER_STATE_STOP; + pc->cross_fade_seconds = 0; + pc->mixramp_db = 0; + pc->mixramp_delay_seconds = nanf(""); + + return pc; } -void pc_deinit(void) +void +pc_free(struct player_control *pc) { - g_cond_free(pc.cond); - g_mutex_free(pc.mutex); + g_cond_free(pc->cond); + g_mutex_free(pc->mutex); + g_free(pc); } void -player_wait_decoder(struct decoder_control *dc) +player_wait_decoder(struct player_control *pc, struct decoder_control *dc) { + assert(pc != NULL); + assert(dc != NULL); + assert(dc->player_control == pc); + /* during this function, the decoder lock is held, because we're waiting for the decoder thread */ - g_cond_wait(pc.cond, dc->mutex); + g_cond_wait(pc->cond, dc->mutex); } void -pc_song_deleted(const struct song *song) +pc_song_deleted(struct player_control *pc, const struct song *song) { - if (pc.errored_song == song) { - pc.error = PLAYER_ERROR_NOERROR; - pc.errored_song = NULL; + if (pc->errored_song == song) { + pc->error = PLAYER_ERROR_NOERROR; + pc->errored_song = NULL; } } static void -player_command_wait_locked(void) +player_command_wait_locked(struct player_control *pc) { - while (pc.command != PLAYER_COMMAND_NONE) - g_cond_wait(main_cond, pc.mutex); + while (pc->command != PLAYER_COMMAND_NONE) + g_cond_wait(main_cond, pc->mutex); } static void -player_command_locked(enum player_command cmd) +player_command_locked(struct player_control *pc, enum player_command cmd) { - assert(pc.command == PLAYER_COMMAND_NONE); + assert(pc->command == PLAYER_COMMAND_NONE); - pc.command = cmd; - player_signal(); - player_command_wait_locked(); + pc->command = cmd; + player_signal(pc); + player_command_wait_locked(pc); } static void -player_command(enum player_command cmd) +player_command(struct player_control *pc, enum player_command cmd) { - player_lock(); - player_command_locked(cmd); - player_unlock(); + player_lock(pc); + player_command_locked(pc, cmd); + player_unlock(pc); } void -pc_play(struct song *song) +pc_play(struct player_control *pc, struct song *song) { assert(song != NULL); - player_lock(); + player_lock(pc); - if (pc.state != PLAYER_STATE_STOP) - player_command_locked(PLAYER_COMMAND_STOP); + if (pc->state != PLAYER_STATE_STOP) + player_command_locked(pc, PLAYER_COMMAND_STOP); - assert(pc.next_song == NULL); + assert(pc->next_song == NULL); - pc_enqueue_song_locked(song); + pc_enqueue_song_locked(pc, song); - assert(pc.next_song == NULL); + assert(pc->next_song == NULL); - player_unlock(); + player_unlock(pc); idle_add(IDLE_PLAYER); } -void pc_cancel(void) +void +pc_cancel(struct player_control *pc) { - player_command(PLAYER_COMMAND_CANCEL); - assert(pc.next_song == NULL); + player_command(pc, PLAYER_COMMAND_CANCEL); + assert(pc->next_song == NULL); } void -pc_stop(void) +pc_stop(struct player_control *pc) { - player_command(PLAYER_COMMAND_CLOSE_AUDIO); - assert(pc.next_song == NULL); + player_command(pc, PLAYER_COMMAND_CLOSE_AUDIO); + assert(pc->next_song == NULL); idle_add(IDLE_PLAYER); } void -pc_update_audio(void) +pc_update_audio(struct player_control *pc) { - player_command(PLAYER_COMMAND_UPDATE_AUDIO); + player_command(pc, PLAYER_COMMAND_UPDATE_AUDIO); } void -pc_kill(void) +pc_kill(struct player_control *pc) { - assert(pc.thread != NULL); + assert(pc->thread != NULL); - player_command(PLAYER_COMMAND_EXIT); - g_thread_join(pc.thread); - pc.thread = NULL; + player_command(pc, PLAYER_COMMAND_EXIT); + g_thread_join(pc->thread); + pc->thread = NULL; idle_add(IDLE_PLAYER); } void -pc_pause(void) +pc_pause(struct player_control *pc) { - player_lock(); + player_lock(pc); - if (pc.state != PLAYER_STATE_STOP) { - player_command_locked(PLAYER_COMMAND_PAUSE); + if (pc->state != PLAYER_STATE_STOP) { + player_command_locked(pc, PLAYER_COMMAND_PAUSE); idle_add(IDLE_PLAYER); } - player_unlock(); + player_unlock(pc); } static void -pc_pause_locked(void) +pc_pause_locked(struct player_control *pc) { - if (pc.state != PLAYER_STATE_STOP) { - player_command_locked(PLAYER_COMMAND_PAUSE); + if (pc->state != PLAYER_STATE_STOP) { + player_command_locked(pc, PLAYER_COMMAND_PAUSE); idle_add(IDLE_PLAYER); } } void -pc_set_pause(bool pause_flag) +pc_set_pause(struct player_control *pc, bool pause_flag) { - player_lock(); + player_lock(pc); - switch (pc.state) { + switch (pc->state) { case PLAYER_STATE_STOP: break; case PLAYER_STATE_PLAY: if (pause_flag) - pc_pause_locked(); + pc_pause_locked(pc); break; case PLAYER_STATE_PAUSE: if (!pause_flag) - pc_pause_locked(); + pc_pause_locked(pc); break; } - player_unlock(); + player_unlock(pc); } void -pc_get_status(struct player_status *status) +pc_get_status(struct player_control *pc, struct player_status *status) { - player_lock(); - player_command_locked(PLAYER_COMMAND_REFRESH); + player_lock(pc); + player_command_locked(pc, PLAYER_COMMAND_REFRESH); - status->state = pc.state; + status->state = pc->state; - if (pc.state != PLAYER_STATE_STOP) { - status->bit_rate = pc.bit_rate; - status->audio_format = pc.audio_format; - status->total_time = pc.total_time; - status->elapsed_time = pc.elapsed_time; + if (pc->state != PLAYER_STATE_STOP) { + status->bit_rate = pc->bit_rate; + status->audio_format = pc->audio_format; + status->total_time = pc->total_time; + status->elapsed_time = pc->elapsed_time; } - player_unlock(); + player_unlock(pc); } enum player_state -pc_get_state(void) +pc_get_state(struct player_control *pc) { - return pc.state; + return pc->state; } void -pc_clear_error(void) +pc_clear_error(struct player_control *pc) { - player_lock(); - pc.error = PLAYER_ERROR_NOERROR; - pc.errored_song = NULL; - player_unlock(); + player_lock(pc); + pc->error = PLAYER_ERROR_NOERROR; + pc->errored_song = NULL; + player_unlock(pc); } enum player_error -pc_get_error(void) +pc_get_error(struct player_control *pc) { - return pc.error; + return pc->error; } static char * -pc_errored_song_uri(void) +pc_errored_song_uri(struct player_control *pc) { - return song_get_uri(pc.errored_song); + return song_get_uri(pc->errored_song); } char * -pc_get_error_message(void) +pc_get_error_message(struct player_control *pc) { char *error; char *uri; - switch (pc.error) { + switch (pc->error) { case PLAYER_ERROR_NOERROR: return NULL; case PLAYER_ERROR_FILENOTFOUND: - uri = pc_errored_song_uri(); + uri = pc_errored_song_uri(pc); error = g_strdup_printf("file \"%s\" does not exist or is inaccessible", uri); g_free(uri); return error; case PLAYER_ERROR_FILE: - uri = pc_errored_song_uri(); + uri = pc_errored_song_uri(pc); error = g_strdup_printf("problems decoding \"%s\"", uri); g_free(uri); return error; @@ -274,7 +284,7 @@ pc_get_error_message(void) return g_strdup("system error occured"); case PLAYER_ERROR_UNKTYPE: - uri = pc_errored_song_uri(); + uri = pc_errored_song_uri(pc); error = g_strdup_printf("file type of \"%s\" is unknown", uri); g_free(uri); return error; @@ -285,40 +295,40 @@ pc_get_error_message(void) } static void -pc_enqueue_song_locked(struct song *song) +pc_enqueue_song_locked(struct player_control *pc, struct song *song) { assert(song != NULL); - assert(pc.next_song == NULL); + assert(pc->next_song == NULL); - pc.next_song = song; - player_command_locked(PLAYER_COMMAND_QUEUE); + pc->next_song = song; + player_command_locked(pc, PLAYER_COMMAND_QUEUE); } void -pc_enqueue_song(struct song *song) +pc_enqueue_song(struct player_control *pc, struct song *song) { assert(song != NULL); - player_lock(); - pc_enqueue_song_locked(song); - player_unlock(); + player_lock(pc); + pc_enqueue_song_locked(pc, song); + player_unlock(pc); } bool -pc_seek(struct song *song, float seek_time) +pc_seek(struct player_control *pc, struct song *song, float seek_time) { assert(song != NULL); - if (pc.state == PLAYER_STATE_STOP) + if (pc->state == PLAYER_STATE_STOP) return false; - player_lock(); - pc.next_song = song; - pc.seek_where = seek_time; - player_command_locked(PLAYER_COMMAND_SEEK); - player_unlock(); + player_lock(pc); + pc->next_song = song; + pc->seek_where = seek_time; + player_command_locked(pc, PLAYER_COMMAND_SEEK); + player_unlock(pc); - assert(pc.next_song == NULL); + assert(pc->next_song == NULL); idle_add(IDLE_PLAYER); @@ -326,51 +336,51 @@ pc_seek(struct song *song, float seek_time) } float -pc_get_cross_fade(void) +pc_get_cross_fade(const struct player_control *pc) { - return pc.cross_fade_seconds; + return pc->cross_fade_seconds; } void -pc_set_cross_fade(float cross_fade_seconds) +pc_set_cross_fade(struct player_control *pc, float cross_fade_seconds) { if (cross_fade_seconds < 0) cross_fade_seconds = 0; - pc.cross_fade_seconds = cross_fade_seconds; + pc->cross_fade_seconds = cross_fade_seconds; idle_add(IDLE_OPTIONS); } float -pc_get_mixramp_db(void) +pc_get_mixramp_db(const struct player_control *pc) { - return pc.mixramp_db; + return pc->mixramp_db; } void -pc_set_mixramp_db(float mixramp_db) +pc_set_mixramp_db(struct player_control *pc, float mixramp_db) { - pc.mixramp_db = mixramp_db; + pc->mixramp_db = mixramp_db; idle_add(IDLE_OPTIONS); } float -pc_get_mixramp_delay(void) +pc_get_mixramp_delay(const struct player_control *pc) { - return pc.mixramp_delay_seconds; + return pc->mixramp_delay_seconds; } void -pc_set_mixramp_delay(float mixramp_delay_seconds) +pc_set_mixramp_delay(struct player_control *pc, float mixramp_delay_seconds) { - pc.mixramp_delay_seconds = mixramp_delay_seconds; + pc->mixramp_delay_seconds = mixramp_delay_seconds; idle_add(IDLE_OPTIONS); } double -pc_get_total_play_time(void) +pc_get_total_play_time(const struct player_control *pc) { - return pc.total_play_time; + return pc->total_play_time; } diff --git a/src/player_control.h b/src/player_control.h index 76c47609a..d37413b55 100644 --- a/src/player_control.h +++ b/src/player_control.h @@ -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 diff --git a/src/player_thread.c b/src/player_thread.c index cce51c1a7..d51263477 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -48,6 +48,8 @@ enum xfade_state { }; struct player { + struct player_control *pc; + struct decoder_control *dc; struct music_pipe *pipe; @@ -117,19 +119,21 @@ struct player { static struct music_buffer *player_buffer; -static void player_command_finished_locked(void) +static void +player_command_finished_locked(struct player_control *pc) { - assert(pc.command != PLAYER_COMMAND_NONE); + assert(pc->command != PLAYER_COMMAND_NONE); - pc.command = PLAYER_COMMAND_NONE; + pc->command = PLAYER_COMMAND_NONE; g_cond_signal(main_cond); } -static void player_command_finished(void) +static void +player_command_finished(struct player_control *pc) { - player_lock(); - player_command_finished_locked(); - player_unlock(); + player_lock(pc); + player_command_finished_locked(pc); + player_unlock(pc); } /** @@ -140,12 +144,13 @@ static void player_command_finished(void) static void player_dc_start(struct player *player, struct music_pipe *pipe) { + struct player_control *pc = player->pc; struct decoder_control *dc = player->dc; - assert(player->queued || pc.command == PLAYER_COMMAND_SEEK); - assert(pc.next_song != NULL); + assert(player->queued || pc->command == PLAYER_COMMAND_SEEK); + assert(pc->next_song != NULL); - dc_start(dc, pc.next_song, player_buffer, pipe); + dc_start(dc, pc->next_song, player_buffer, pipe); } /** @@ -208,41 +213,42 @@ player_dc_stop(struct player *player) static bool player_wait_for_decoder(struct player *player) { + struct player_control *pc = player->pc; struct decoder_control *dc = player->dc; - assert(player->queued || pc.command == PLAYER_COMMAND_SEEK); - assert(pc.next_song != NULL); + assert(player->queued || pc->command == PLAYER_COMMAND_SEEK); + assert(pc->next_song != NULL); player->queued = false; if (decoder_lock_has_failed(dc)) { - player_lock(); - pc.errored_song = dc->song; - pc.error = PLAYER_ERROR_FILE; - pc.next_song = NULL; - player_unlock(); + player_lock(pc); + pc->errored_song = dc->song; + pc->error = PLAYER_ERROR_FILE; + pc->next_song = NULL; + player_unlock(pc); return false; } - player->song = pc.next_song; + player->song = pc->next_song; player->elapsed_time = 0.0; /* set the "starting" flag, which will be cleared by player_check_decoder_startup() */ player->decoder_starting = true; - player_lock(); + player_lock(pc); /* update player_control's song information */ - pc.total_time = song_get_duration(pc.next_song); - pc.bit_rate = 0; - audio_format_clear(&pc.audio_format); + pc->total_time = song_get_duration(pc->next_song); + pc->bit_rate = 0; + audio_format_clear(&pc->audio_format); /* clear the queued song */ - pc.next_song = NULL; + pc->next_song = NULL; - player_unlock(); + player_unlock(pc); /* call syncPlaylistWithQueue() in the main thread */ event_pipe_emit(PIPE_EVENT_PLAYLIST); @@ -280,6 +286,7 @@ real_song_duration(const struct song *song, double decoder_duration) static bool player_check_decoder_startup(struct player *player) { + struct player_control *pc = player->pc; struct decoder_control *dc = player->dc; assert(player->decoder_starting); @@ -290,10 +297,10 @@ player_check_decoder_startup(struct player *player) /* the decoder failed */ decoder_unlock(dc); - player_lock(); - pc.errored_song = dc->song; - pc.error = PLAYER_ERROR_FILE; - player_unlock(); + player_lock(pc); + pc->errored_song = dc->song; + pc->error = PLAYER_ERROR_FILE; + player_unlock(pc); return false; } else if (!decoder_is_starting(dc)) { @@ -302,15 +309,15 @@ player_check_decoder_startup(struct player *player) decoder_unlock(dc); if (audio_format_defined(&player->play_audio_format) && - !audio_output_all_wait(1)) + !audio_output_all_wait(pc, 1)) /* the output devices havn't finished playing all chunks yet - wait for that */ return true; - player_lock(); - pc.total_time = real_song_duration(dc->song, dc->total_time); - pc.audio_format = dc->in_audio_format; - player_unlock(); + player_lock(pc); + pc->total_time = real_song_duration(dc->song, dc->total_time); + pc->audio_format = dc->in_audio_format; + player_unlock(pc); player->play_audio_format = dc->out_audio_format; player->decoder_starting = false; @@ -323,13 +330,13 @@ player_check_decoder_startup(struct player *player) "while playing \"%s\"", uri); g_free(uri); - player_lock(); - pc.error = PLAYER_ERROR_AUDIO; + player_lock(pc); + pc->error = PLAYER_ERROR_AUDIO; /* pause: the user may resume playback as soon as an audio output becomes available */ - pc.state = PLAYER_STATE_PAUSE; - player_unlock(); + pc->state = PLAYER_STATE_PAUSE; + player_unlock(pc); player->paused = true; return true; @@ -339,7 +346,7 @@ player_check_decoder_startup(struct player *player) } else { /* the decoder is not yet ready; wait some more */ - player_wait_decoder(dc); + player_wait_decoder(pc, dc); decoder_unlock(dc); return true; @@ -393,10 +400,11 @@ player_send_silence(struct player *player) */ static bool player_seek_decoder(struct player *player) { - struct song *song = pc.next_song; + struct player_control *pc = player->pc; + struct song *song = pc->next_song; struct decoder_control *dc = player->dc; - assert(pc.next_song != NULL); + assert(pc->next_song != NULL); if (decoder_current_song(dc) != song) { /* the decoder is already decoding the "next" song - @@ -412,7 +420,7 @@ static bool player_seek_decoder(struct player *player) player_dc_start(player, player->pipe); if (!player_wait_for_decoder(player)) { /* decoder failure */ - player_command_finished(); + player_command_finished(pc); return false; } } else { @@ -424,7 +432,7 @@ static bool player_seek_decoder(struct player *player) player->pipe = dc->pipe; } - pc.next_song = NULL; + pc->next_song = NULL; player->queued = false; } @@ -433,28 +441,28 @@ static bool player_seek_decoder(struct player *player) while (player->decoder_starting) { if (!player_check_decoder_startup(player)) { /* decoder failure */ - player_command_finished(); + player_command_finished(pc); return false; } } /* send the SEEK command */ - double where = pc.seek_where; - if (where > pc.total_time) - where = pc.total_time - 0.1; + double where = pc->seek_where; + if (where > pc->total_time) + where = pc->total_time - 0.1; if (where < 0.0) where = 0.0; if (!dc_seek(dc, where + song->start_ms / 1000.0)) { /* decoder failure */ - player_command_finished(); + player_command_finished(pc); return false; } player->elapsed_time = where; - player_command_finished(); + player_command_finished(pc); player->xfade = XFADE_UNKNOWN; @@ -471,9 +479,10 @@ static bool player_seek_decoder(struct player *player) */ static void player_process_command(struct player *player) { + struct player_control *pc = player->pc; G_GNUC_UNUSED struct decoder_control *dc = player->dc; - switch (pc.command) { + switch (pc->command) { case PLAYER_COMMAND_NONE: case PLAYER_COMMAND_STOP: case PLAYER_COMMAND_EXIT: @@ -481,95 +490,95 @@ static void player_process_command(struct player *player) break; case PLAYER_COMMAND_UPDATE_AUDIO: - player_unlock(); + player_unlock(pc); audio_output_all_enable_disable(); - player_lock(); - player_command_finished_locked(); + player_lock(pc); + player_command_finished_locked(pc); break; case PLAYER_COMMAND_QUEUE: - assert(pc.next_song != NULL); + assert(pc->next_song != NULL); assert(!player->queued); assert(!player_dc_at_next_song(player)); player->queued = true; - player_command_finished_locked(); + player_command_finished_locked(pc); break; case PLAYER_COMMAND_PAUSE: - player_unlock(); + player_unlock(pc); player->paused = !player->paused; if (player->paused) { audio_output_all_pause(); - player_lock(); + player_lock(pc); - pc.state = PLAYER_STATE_PAUSE; + pc->state = PLAYER_STATE_PAUSE; } else if (!audio_format_defined(&player->play_audio_format)) { /* the decoder hasn't provided an audio format yet - don't open the audio device yet */ - player_lock(); + player_lock(pc); - pc.state = PLAYER_STATE_PLAY; + pc->state = PLAYER_STATE_PLAY; } else if (audio_output_all_open(&player->play_audio_format, player_buffer)) { /* unpaused, continue playing */ - player_lock(); + player_lock(pc); - pc.state = PLAYER_STATE_PLAY; + pc->state = PLAYER_STATE_PLAY; } else { /* the audio device has failed - rollback to pause mode */ - pc.error = PLAYER_ERROR_AUDIO; + pc->error = PLAYER_ERROR_AUDIO; player->paused = true; - player_lock(); + player_lock(pc); } - player_command_finished_locked(); + player_command_finished_locked(pc); break; case PLAYER_COMMAND_SEEK: - player_unlock(); + player_unlock(pc); player_seek_decoder(player); - player_lock(); + player_lock(pc); break; case PLAYER_COMMAND_CANCEL: - if (pc.next_song == NULL) { + if (pc->next_song == NULL) { /* the cancel request arrived too late, we're already playing the queued song... stop everything now */ - pc.command = PLAYER_COMMAND_STOP; + pc->command = PLAYER_COMMAND_STOP; return; } if (player_dc_at_next_song(player)) { /* the decoder is already decoding the song - stop it and reset the position */ - player_unlock(); + player_unlock(pc); player_dc_stop(player); - player_lock(); + player_lock(pc); } - pc.next_song = NULL; + pc->next_song = NULL; player->queued = false; - player_command_finished_locked(); + player_command_finished_locked(pc); break; case PLAYER_COMMAND_REFRESH: if (audio_format_defined(&player->play_audio_format) && !player->paused) { - player_unlock(); + player_unlock(pc); audio_output_all_check(); - player_lock(); + player_lock(pc); } - pc.elapsed_time = audio_output_all_get_elapsed_time(); - if (pc.elapsed_time < 0.0) - pc.elapsed_time = player->elapsed_time; + pc->elapsed_time = audio_output_all_get_elapsed_time(); + if (pc->elapsed_time < 0.0) + pc->elapsed_time = player->elapsed_time; - player_command_finished_locked(); + player_command_finished_locked(pc); break; } } @@ -605,7 +614,8 @@ update_song_tag(struct song *song, const struct tag *new_tag) * Player lock is not held. */ static bool -play_chunk(struct song *song, struct music_chunk *chunk, +play_chunk(struct player_control *pc, + struct song *song, struct music_chunk *chunk, const struct audio_format *format) { assert(music_chunk_check_format(chunk, format)); @@ -618,14 +628,14 @@ play_chunk(struct song *song, struct music_chunk *chunk, return true; } - pc.bit_rate = chunk->bit_rate; + pc->bit_rate = chunk->bit_rate; /* send the chunk to the audio outputs */ if (!audio_output_all_play(chunk)) return false; - pc.total_play_time += (double)chunk->length / + pc->total_play_time += (double)chunk->length / audio_format_time_to_size(format); return true; } @@ -639,9 +649,10 @@ play_chunk(struct song *song, struct music_chunk *chunk, static bool play_next_chunk(struct player *player) { + struct player_control *pc = player->pc; struct decoder_control *dc = player->dc; - if (!audio_output_all_wait(64)) + if (!audio_output_all_wait(pc, 64)) /* the output pipe is still large enough, don't send another chunk */ return true; @@ -678,7 +689,7 @@ play_next_chunk(struct player *player) other_chunk->tag); other_chunk->tag = NULL; - if (isnan(pc.mixramp_delay_seconds)) { + if (isnan(pc->mixramp_delay_seconds)) { chunk->mix_ratio = ((float)cross_fade_position) / player->cross_fade_chunks; } else { @@ -713,7 +724,7 @@ play_next_chunk(struct player *player) } else { /* wait for the decoder */ decoder_signal(dc); - player_wait_decoder(dc); + player_wait_decoder(pc, dc); decoder_unlock(dc); return true; @@ -736,19 +747,20 @@ play_next_chunk(struct player *player) /* play the current chunk */ - if (!play_chunk(player->song, chunk, &player->play_audio_format)) { + if (!play_chunk(player->pc, player->song, chunk, + &player->play_audio_format)) { music_buffer_return(player_buffer, chunk); - player_lock(); + player_lock(pc); - pc.error = PLAYER_ERROR_AUDIO; + pc->error = PLAYER_ERROR_AUDIO; /* pause: the user may resume playback as soon as an audio output becomes available */ - pc.state = PLAYER_STATE_PAUSE; + pc->state = PLAYER_STATE_PAUSE; player->paused = true; - player_unlock(); + player_unlock(pc); return false; } @@ -758,7 +770,7 @@ play_next_chunk(struct player *player) larger block at a time */ decoder_lock(dc); if (!decoder_is_idle(dc) && - music_pipe_size(dc->pipe) <= (pc.buffered_before_play + + music_pipe_size(dc->pipe) <= (pc->buffered_before_play + music_buffer_size(player_buffer) * 3) / 4) decoder_signal(dc); decoder_unlock(dc); @@ -800,9 +812,10 @@ player_song_border(struct player *player) * basically a state machine, which multiplexes data between the * decoder thread and the output threads. */ -static void do_play(struct decoder_control *dc) +static void do_play(struct player_control *pc, struct decoder_control *dc) { struct player player = { + .pc = pc, .dc = dc, .buffering = true, .decoder_starting = false, @@ -816,42 +829,42 @@ static void do_play(struct decoder_control *dc) .elapsed_time = 0.0, }; - player_unlock(); + player_unlock(pc); player.pipe = music_pipe_new(); player_dc_start(&player, player.pipe); if (!player_wait_for_decoder(&player)) { player_dc_stop(&player); - player_command_finished(); + player_command_finished(pc); music_pipe_free(player.pipe); event_pipe_emit(PIPE_EVENT_PLAYLIST); - player_lock(); + player_lock(pc); return; } - player_lock(); - pc.state = PLAYER_STATE_PLAY; - player_command_finished_locked(); + player_lock(pc); + pc->state = PLAYER_STATE_PLAY; + player_command_finished_locked(pc); while (true) { player_process_command(&player); - if (pc.command == PLAYER_COMMAND_STOP || - pc.command == PLAYER_COMMAND_EXIT || - pc.command == PLAYER_COMMAND_CLOSE_AUDIO) { - player_unlock(); + if (pc->command == PLAYER_COMMAND_STOP || + pc->command == PLAYER_COMMAND_EXIT || + pc->command == PLAYER_COMMAND_CLOSE_AUDIO) { + player_unlock(pc); audio_output_all_cancel(); break; } - player_unlock(); + player_unlock(pc); if (player.buffering) { /* buffering at the start of the song - wait until the buffer is large enough, to prevent stuttering on slow machines */ - if (music_pipe_size(player.pipe) < pc.buffered_before_play && + if (music_pipe_size(player.pipe) < pc->buffered_before_play && !decoder_lock_is_idle(dc)) { /* not enough decoded buffer space yet */ @@ -863,9 +876,9 @@ static void do_play(struct decoder_control *dc) decoder_lock(dc); /* XXX race condition: check decoder again */ - player_wait_decoder(dc); + player_wait_decoder(pc, dc); decoder_unlock(dc); - player_lock(); + player_lock(pc); continue; } else { /* buffering is complete */ @@ -889,7 +902,7 @@ static void do_play(struct decoder_control *dc) !dc_seek(dc, song->start_ms / 1000.0)) player_dc_stop(&player); - player_lock(); + player_lock(pc); continue; } @@ -918,9 +931,9 @@ static void do_play(struct decoder_control *dc) calculate how many chunks will be required for it */ player.cross_fade_chunks = - cross_fade_calc(pc.cross_fade_seconds, dc->total_time, - pc.mixramp_db, - pc.mixramp_delay_seconds, + cross_fade_calc(pc->cross_fade_seconds, dc->total_time, + pc->mixramp_db, + pc->mixramp_delay_seconds, dc->replay_gain_db, dc->replay_gain_prev_db, dc->mixramp_start, @@ -928,7 +941,7 @@ static void do_play(struct decoder_control *dc) &dc->out_audio_format, &player.play_audio_format, music_buffer_size(player_buffer) - - pc.buffered_before_play); + pc->buffered_before_play); if (player.cross_fade_chunks > 0) { player.xfade = XFADE_ENABLED; player.cross_fading = false; @@ -939,10 +952,10 @@ static void do_play(struct decoder_control *dc) } if (player.paused) { - player_lock(); + player_lock(pc); - if (pc.command == PLAYER_COMMAND_NONE) - player_wait(); + if (pc->command == PLAYER_COMMAND_NONE) + player_wait(pc); continue; } else if (!music_pipe_empty(player.pipe)) { /* at least one music chunk is ready - send it @@ -979,7 +992,7 @@ static void do_play(struct decoder_control *dc) break; } - player_lock(); + player_lock(pc); } player_dc_stop(&player); @@ -990,113 +1003,116 @@ static void do_play(struct decoder_control *dc) if (player.cross_fade_tag != NULL) tag_free(player.cross_fade_tag); - player_lock(); + player_lock(pc); if (player.queued) { - assert(pc.next_song != NULL); - pc.next_song = NULL; + assert(pc->next_song != NULL); + pc->next_song = NULL; } - pc.state = PLAYER_STATE_STOP; + pc->state = PLAYER_STATE_STOP; - player_unlock(); + player_unlock(pc); event_pipe_emit(PIPE_EVENT_PLAYLIST); - player_lock(); + player_lock(pc); } -static gpointer player_task(G_GNUC_UNUSED gpointer arg) +static gpointer +player_task(gpointer arg) { + struct player_control *pc = arg; struct decoder_control dc; - dc_init(&dc); + dc_init(&dc, pc); decoder_thread_start(&dc); - player_buffer = music_buffer_new(pc.buffer_chunks); + player_buffer = music_buffer_new(pc->buffer_chunks); - player_lock(); + player_lock(pc); while (1) { - switch (pc.command) { + switch (pc->command) { case PLAYER_COMMAND_QUEUE: - assert(pc.next_song != NULL); + assert(pc->next_song != NULL); - do_play(&dc); + do_play(pc, &dc); break; case PLAYER_COMMAND_STOP: - player_unlock(); + player_unlock(pc); audio_output_all_cancel(); - player_lock(); + player_lock(pc); /* fall through */ case PLAYER_COMMAND_SEEK: case PLAYER_COMMAND_PAUSE: - pc.next_song = NULL; - player_command_finished_locked(); + pc->next_song = NULL; + player_command_finished_locked(pc); break; case PLAYER_COMMAND_CLOSE_AUDIO: - player_unlock(); + player_unlock(pc); audio_output_all_release(); - player_lock(); - player_command_finished_locked(); + player_lock(pc); + player_command_finished_locked(pc); #ifndef NDEBUG /* in the DEBUG build, check for leaked music_chunk objects by freeing the music_buffer */ music_buffer_free(player_buffer); - player_buffer = music_buffer_new(pc.buffer_chunks); + player_buffer = music_buffer_new(pc->buffer_chunks); #endif break; case PLAYER_COMMAND_UPDATE_AUDIO: - player_unlock(); + player_unlock(pc); audio_output_all_enable_disable(); - player_lock(); - player_command_finished_locked(); + player_lock(pc); + player_command_finished_locked(pc); break; case PLAYER_COMMAND_EXIT: - player_unlock(); + player_unlock(pc); dc_quit(&dc); dc_deinit(&dc); audio_output_all_close(); music_buffer_free(player_buffer); - player_command_finished(); + player_command_finished(pc); return NULL; case PLAYER_COMMAND_CANCEL: - pc.next_song = NULL; - player_command_finished_locked(); + pc->next_song = NULL; + player_command_finished_locked(pc); break; case PLAYER_COMMAND_REFRESH: /* no-op when not playing */ - player_command_finished_locked(); + player_command_finished_locked(pc); break; case PLAYER_COMMAND_NONE: - player_wait(); + player_wait(pc); break; } } } -void player_create(void) +void +player_create(struct player_control *pc) { - assert(pc.thread == NULL); + assert(pc->thread == NULL); GError *e = NULL; - pc.thread = g_thread_create(player_task, NULL, true, &e); - if (pc.thread == NULL) + pc->thread = g_thread_create(player_task, pc, true, &e); + if (pc->thread == NULL) MPD_ERROR("Failed to spawn player task: %s", e->message); } diff --git a/src/player_thread.h b/src/player_thread.h index e645b1d09..2333c0c54 100644 --- a/src/player_thread.h +++ b/src/player_thread.h @@ -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 diff --git a/src/playlist.c b/src/playlist.c index 4a1e54814..d45e7622a 100644 --- a/src/playlist.c +++ b/src/playlist.c @@ -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); } diff --git a/src/playlist.h b/src/playlist.h index 3ba90ff91..e1e6eff85 100644 --- a/src/playlist.h +++ b/src/playlist.h @@ -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 diff --git a/src/playlist_control.c b/src/playlist_control.c index ce9bc8442..c3592dab0 100644 --- a/src/playlist_control.c +++ b/src/playlist_control.c @@ -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); } diff --git a/src/playlist_edit.c b/src/playlist_edit.c index c54b72750..e61c2a603 100644 --- a/src/playlist_edit.c +++ b/src/playlist_edit.c @@ -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); } diff --git a/src/playlist_global.c b/src/playlist_global.c index 2833b62ed..1ff9f8f21 100644 --- a/src/playlist_global.c +++ b/src/playlist_global.c @@ -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 diff --git a/src/playlist_internal.h b/src/playlist_internal.h index 9d205188f..173ff9cea 100644 --- a/src/playlist_internal.h +++ b/src/playlist_internal.h @@ -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 diff --git a/src/playlist_queue.c b/src/playlist_queue.c index 43621da9f..e0730fd08 100644 --- a/src/playlist_queue.c +++ b/src/playlist_queue.c @@ -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) diff --git a/src/playlist_queue.h b/src/playlist_queue.h index 9ffa51198..9c706898e 100644 --- a/src/playlist_queue.h +++ b/src/playlist_queue.h @@ -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 diff --git a/src/playlist_save.c b/src/playlist_save.c index 8ddc93ec9..d983b2d3c 100644 --- a/src/playlist_save.c +++ b/src/playlist_save.c @@ -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); diff --git a/src/playlist_save.h b/src/playlist_save.h index a0131cf7f..441ac6b84 100644 --- a/src/playlist_save.h +++ b/src/playlist_save.h @@ -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 diff --git a/src/playlist_state.c b/src/playlist_state.c index bb9897e01..2a2228d05 100644 --- a/src/playlist_state.c +++ b/src/playlist_state.c @@ -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) ^ diff --git a/src/playlist_state.h b/src/playlist_state.h index 8ca3657f2..c4ce0fcb0 100644 --- a/src/playlist_state.h +++ b/src/playlist_state.h @@ -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 diff --git a/src/state_file.c b/src/state_file.c index 55af25d5c..fe64ae0b4 100644 --- a/src/state_file.c +++ b/src/state_file.c @@ -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); } diff --git a/src/state_file.h b/src/state_file.h index ec01fcbed..38d3f74ed 100644 --- a/src/state_file.h +++ b/src/state_file.h @@ -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); diff --git a/src/stats.c b/src/stats.c index 673d531ec..5a90fad84 100644 --- a/src/stats.c +++ b/src/stats.c @@ -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; diff --git a/src/update_remove.c b/src/update_remove.c index f7c2342a2..8bec5fd6d 100644 --- a/src/update_remove.c +++ b/src/update_remove.c @@ -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); diff --git a/test/run_output.c b/test/run_output.c index 5028068ff..8ba5c1d8a 100644 --- a/test/run_output.c +++ b/test/run_output.c @@ -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); |