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.
26 #include "playlist_state.h"
28 #include "player_control.h"
29 #include "queue_save.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
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
);
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
,
74 fprintf(fp
, "%s%i\n", PLAYLIST_STATE_FILE_TIME
,
75 (int)player_status
.elapsed_time
);
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
,
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
,
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
);
105 playlist_state_load(FILE *fp
, struct playlist
*playlist
, char *buffer
)
109 if (!fgets(buffer
, PLAYLIST_BUFFER_SIZE
, fp
)) {
110 g_warning("No playlist in state file");
114 while (!g_str_has_prefix(buffer
, PLAYLIST_STATE_FILE_PLAYLIST_END
)) {
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
);
126 queue_increment_version(&playlist
->queue
);
130 playlist_state_restore(const char *line
, FILE *fp
, struct playlist
*playlist
)
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
))
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
)) {
151 if (g_str_has_prefix(buffer
, PLAYLIST_STATE_FILE_TIME
)) {
153 atoi(&(buffer
[strlen(PLAYLIST_STATE_FILE_TIME
)]));
154 } else if (g_str_has_prefix(buffer
, PLAYLIST_STATE_FILE_REPEAT
)) {
156 (&(buffer
[strlen(PLAYLIST_STATE_FILE_REPEAT
)]),
158 playlist_set_repeat(playlist
, true);
160 playlist_set_repeat(playlist
, false);
161 } else if (g_str_has_prefix(buffer
, PLAYLIST_STATE_FILE_SINGLE
)) {
163 (&(buffer
[strlen(PLAYLIST_STATE_FILE_SINGLE
)]),
165 playlist_set_single(playlist
, true);
167 playlist_set_single(playlist
, false);
168 } else if (g_str_has_prefix(buffer
, PLAYLIST_STATE_FILE_CONSUME
)) {
170 (&(buffer
[strlen(PLAYLIST_STATE_FILE_CONSUME
)]),
172 playlist_set_consume(playlist
, true);
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
)) {
183 strcmp(buffer
+ strlen(PLAYLIST_STATE_FILE_RANDOM
),
185 } else if (g_str_has_prefix(buffer
, PLAYLIST_STATE_FILE_CURRENT
)) {
186 current
= atoi(&(buffer
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
))
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
)
207 if (state
== PLAYER_STATE_STOP
/* && config_option */)
208 playlist
->current
= current
;
209 else if (seek_time
== 0)
210 playlist_play(playlist
, current
);
212 playlist_seek_song(playlist
, current
, seek_time
);
214 if (state
== PLAYER_STATE_PAUSE
)
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)
232 (playlist
->current
>= 0
233 ? (queue_order_to_position(&playlist
->queue
,
234 playlist
->current
) << 16)
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);