configure.ac: Move OpenAL to Audio Output Plugins (nonstreaming), add header.
[mpd-mk.git] / src / playlist_state.c
blob9f057332d1e33a800ce94f1c0929e987528c9b15
1 /*
2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 * Saving and loading the playlist to/from the state file.
25 #include "config.h"
26 #include "playlist_state.h"
27 #include "playlist.h"
28 #include "player_control.h"
29 #include "queue_save.h"
30 #include "path.h"
32 #include <string.h>
33 #include <stdlib.h>
35 #define PLAYLIST_STATE_FILE_STATE "state: "
36 #define PLAYLIST_STATE_FILE_RANDOM "random: "
37 #define PLAYLIST_STATE_FILE_REPEAT "repeat: "
38 #define PLAYLIST_STATE_FILE_SINGLE "single: "
39 #define PLAYLIST_STATE_FILE_CONSUME "consume: "
40 #define PLAYLIST_STATE_FILE_CURRENT "current: "
41 #define PLAYLIST_STATE_FILE_TIME "time: "
42 #define PLAYLIST_STATE_FILE_CROSSFADE "crossfade: "
43 #define PLAYLIST_STATE_FILE_MIXRAMPDB "mixrampdb: "
44 #define PLAYLIST_STATE_FILE_MIXRAMPDELAY "mixrampdelay: "
45 #define PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "playlist_begin"
46 #define PLAYLIST_STATE_FILE_PLAYLIST_END "playlist_end"
48 #define PLAYLIST_STATE_FILE_STATE_PLAY "play"
49 #define PLAYLIST_STATE_FILE_STATE_PAUSE "pause"
50 #define PLAYLIST_STATE_FILE_STATE_STOP "stop"
52 #define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX
54 void
55 playlist_state_save(FILE *fp, const struct playlist *playlist)
57 struct player_status player_status;
59 pc_get_status(&player_status);
61 fprintf(fp, "%s", PLAYLIST_STATE_FILE_STATE);
63 if (playlist->playing) {
64 switch (player_status.state) {
65 case PLAYER_STATE_PAUSE:
66 fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_STATE_PAUSE);
67 break;
68 default:
69 fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_STATE_PLAY);
71 fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_CURRENT,
72 queue_order_to_position(&playlist->queue,
73 playlist->current));
74 fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_TIME,
75 (int)player_status.elapsed_time);
76 } else {
77 fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_STATE_STOP);
79 if (playlist->current >= 0)
80 fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_CURRENT,
81 queue_order_to_position(&playlist->queue,
82 playlist->current));
85 fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_RANDOM,
86 playlist->queue.random);
87 fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_REPEAT,
88 playlist->queue.repeat);
89 fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_SINGLE,
90 playlist->queue.single);
91 fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_CONSUME,
92 playlist->queue.consume);
93 fprintf(fp, "%s%i\n", PLAYLIST_STATE_FILE_CROSSFADE,
94 (int)(pc_get_cross_fade()));
95 fprintf(fp, "%s%f\n", PLAYLIST_STATE_FILE_MIXRAMPDB,
96 pc_get_mixramp_db());
97 fprintf(fp, "%s%f\n", PLAYLIST_STATE_FILE_MIXRAMPDELAY,
98 pc_get_mixramp_delay());
99 fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_PLAYLIST_BEGIN);
100 queue_save(fp, &playlist->queue);
101 fprintf(fp, "%s\n", PLAYLIST_STATE_FILE_PLAYLIST_END);
104 static void
105 playlist_state_load(FILE *fp, struct playlist *playlist, char *buffer)
107 int song;
109 if (!fgets(buffer, PLAYLIST_BUFFER_SIZE, fp)) {
110 g_warning("No playlist in state file");
111 return;
114 while (!g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_PLAYLIST_END)) {
115 g_strchomp(buffer);
117 song = queue_load_song(&playlist->queue, buffer);
119 if (!fgets(buffer, PLAYLIST_BUFFER_SIZE, fp)) {
120 g_warning("'%s' not found in state file",
121 PLAYLIST_STATE_FILE_PLAYLIST_END);
122 break;
126 queue_increment_version(&playlist->queue);
129 bool
130 playlist_state_restore(const char *line, FILE *fp, struct playlist *playlist)
132 int current = -1;
133 int seek_time = 0;
134 int state = PLAYER_STATE_STOP;
135 char buffer[PLAYLIST_BUFFER_SIZE];
136 bool random_mode = false;
138 if (!g_str_has_prefix(line, PLAYLIST_STATE_FILE_STATE))
139 return false;
141 line += sizeof(PLAYLIST_STATE_FILE_STATE) - 1;
143 if (strcmp(line, PLAYLIST_STATE_FILE_STATE_PLAY) == 0)
144 state = PLAYER_STATE_PLAY;
145 else if (strcmp(line, PLAYLIST_STATE_FILE_STATE_PAUSE) == 0)
146 state = PLAYER_STATE_PAUSE;
148 while (fgets(buffer, sizeof(buffer), fp)) {
149 g_strchomp(buffer);
151 if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_TIME)) {
152 seek_time =
153 atoi(&(buffer[strlen(PLAYLIST_STATE_FILE_TIME)]));
154 } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_REPEAT)) {
155 if (strcmp
156 (&(buffer[strlen(PLAYLIST_STATE_FILE_REPEAT)]),
157 "1") == 0) {
158 playlist_set_repeat(playlist, true);
159 } else
160 playlist_set_repeat(playlist, false);
161 } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_SINGLE)) {
162 if (strcmp
163 (&(buffer[strlen(PLAYLIST_STATE_FILE_SINGLE)]),
164 "1") == 0) {
165 playlist_set_single(playlist, true);
166 } else
167 playlist_set_single(playlist, false);
168 } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_CONSUME)) {
169 if (strcmp
170 (&(buffer[strlen(PLAYLIST_STATE_FILE_CONSUME)]),
171 "1") == 0) {
172 playlist_set_consume(playlist, true);
173 } else
174 playlist_set_consume(playlist, false);
175 } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_CROSSFADE)) {
176 pc_set_cross_fade(atoi(buffer + strlen(PLAYLIST_STATE_FILE_CROSSFADE)));
177 } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_MIXRAMPDB)) {
178 pc_set_mixramp_db(atof(buffer + strlen(PLAYLIST_STATE_FILE_MIXRAMPDB)));
179 } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_MIXRAMPDELAY)) {
180 pc_set_mixramp_delay(atof(buffer + strlen(PLAYLIST_STATE_FILE_MIXRAMPDELAY)));
181 } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_RANDOM)) {
182 random_mode =
183 strcmp(buffer + strlen(PLAYLIST_STATE_FILE_RANDOM),
184 "1") == 0;
185 } else if (g_str_has_prefix(buffer, PLAYLIST_STATE_FILE_CURRENT)) {
186 current = atoi(&(buffer
187 [strlen
188 (PLAYLIST_STATE_FILE_CURRENT)]));
189 } else if (g_str_has_prefix(buffer,
190 PLAYLIST_STATE_FILE_PLAYLIST_BEGIN)) {
191 playlist_state_load(fp, playlist, buffer);
195 playlist_set_random(playlist, random_mode);
197 if (!queue_is_empty(&playlist->queue)) {
198 if (!queue_valid_position(&playlist->queue, current))
199 current = 0;
201 /* enable all devices for the first time; this must be
202 called here, after the audio output states were
203 restored, before playback begins */
204 if (state != PLAYER_STATE_STOP)
205 pc_update_audio();
207 if (state == PLAYER_STATE_STOP /* && config_option */)
208 playlist->current = current;
209 else if (seek_time == 0)
210 playlist_play(playlist, current);
211 else
212 playlist_seek_song(playlist, current, seek_time);
214 if (state == PLAYER_STATE_PAUSE)
215 pc_pause();
218 return true;
221 unsigned
222 playlist_state_get_hash(const struct playlist *playlist)
224 struct player_status player_status;
226 pc_get_status(&player_status);
228 return playlist->queue.version ^
229 (player_status.state != PLAYER_STATE_STOP
230 ? ((int)player_status.elapsed_time << 8)
231 : 0) ^
232 (playlist->current >= 0
233 ? (queue_order_to_position(&playlist->queue,
234 playlist->current) << 16)
235 : 0) ^
236 ((int)pc_get_cross_fade() << 20) ^
237 (player_status.state << 24) ^
238 (playlist->queue.random << 27) ^
239 (playlist->queue.repeat << 28) ^
240 (playlist->queue.single << 29) ^
241 (playlist->queue.consume << 30) ^
242 (playlist->queue.random << 31);