player_control.c 5.46 KB
Newer Older
1 2 3
/*
 * Copyright (C) 2003-2009 The Music Player Daemon Project
 * http://www.musicpd.org
4 5 6 7 8 9 10 11 12 13
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
14 15 16 17
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 19
 */

20
#include "player_control.h"
21
#include "decoder_control.h"
22 23
#include "path.h"
#include "log.h"
Max Kellermann's avatar
Max Kellermann committed
24
#include "tag.h"
25
#include "song.h"
26
#include "idle.h"
27
#include "pcm_volume.h"
28
#include "main.h"
29

Max Kellermann's avatar
Max Kellermann committed
30 31 32
#include <assert.h>
#include <stdio.h>

33
struct player_control pc;
34

35
void pc_init(unsigned buffer_chunks, unsigned int buffered_before_play)
36
{
37
	pc.buffer_chunks = buffer_chunks;
38
	pc.buffered_before_play = buffered_before_play;
39 40 41 42

	pc.mutex = g_mutex_new();
	pc.cond = g_cond_new();

43 44 45
	pc.command = PLAYER_COMMAND_NONE;
	pc.error = PLAYER_ERROR_NOERROR;
	pc.state = PLAYER_STATE_STOP;
Max Kellermann's avatar
Max Kellermann committed
46
	pc.cross_fade_seconds = 0;
47 48
}

49 50
void pc_deinit(void)
{
51 52 53 54 55
	g_cond_free(pc.cond);
	g_mutex_free(pc.mutex);
}

void
56
player_wait_decoder(struct decoder_control *dc)
57 58 59
{
	/* during this function, the decoder lock is held, because
	   we're waiting for the decoder thread */
60
	g_cond_wait(pc.cond, dc->mutex);
61 62
}

63 64 65
void
pc_song_deleted(const struct song *song)
{
66 67
	if (pc.errored_song == song) {
		pc.error = PLAYER_ERROR_NOERROR;
68
		pc.errored_song = NULL;
69
	}
70 71
}

72 73 74
static void
player_command_wait_locked(void)
{
75
	while (pc.command != PLAYER_COMMAND_NONE)
76 77 78 79 80
		g_cond_wait(main_cond, pc.mutex);
}

static void
player_command_locked(enum player_command cmd)
81
{
82 83
	assert(pc.command == PLAYER_COMMAND_NONE);

84
	pc.command = cmd;
85
	player_signal();
86 87 88 89 90 91 92 93 94
	player_command_wait_locked();
}

static void
player_command(enum player_command cmd)
{
	player_lock();
	player_command_locked(cmd);
	player_unlock();
95 96
}

97
void
98
pc_play(struct song *song)
99
{
100
	assert(song != NULL);
101 102 103 104

	if (pc.state != PLAYER_STATE_STOP)
		player_command(PLAYER_COMMAND_STOP);

105 106
	assert(pc.next_song == NULL);

107
	pc_enqueue_song(song);
108

109 110
	assert(pc.next_song == NULL);

111
	idle_add(IDLE_PLAYER);
112 113
}

114
void pc_cancel(void)
115
{
116
	player_command(PLAYER_COMMAND_CANCEL);
117
	assert(pc.next_song == NULL);
118
}
119

120 121
void
pc_stop(void)
122
{
123
	player_command(PLAYER_COMMAND_CLOSE_AUDIO);
124
	assert(pc.next_song == NULL);
125 126

	idle_add(IDLE_PLAYER);
127 128
}

129 130 131 132 133 134
void
pc_update_audio(void)
{
	player_command(PLAYER_COMMAND_UPDATE_AUDIO);
}

135 136
void
pc_kill(void)
137
{
138 139
	assert(pc.thread != NULL);

140
	player_command(PLAYER_COMMAND_EXIT);
141 142
	g_thread_join(pc.thread);
	pc.thread = NULL;
143 144

	idle_add(IDLE_PLAYER);
145 146
}

147 148
void
pc_pause(void)
149
{
150
	if (pc.state != PLAYER_STATE_STOP) {
151
		player_command(PLAYER_COMMAND_PAUSE);
152 153
		idle_add(IDLE_PLAYER);
	}
154 155
}

156 157
void
pc_set_pause(bool pause_flag)
158 159 160 161 162 163 164
{
	switch (pc.state) {
	case PLAYER_STATE_STOP:
		break;

	case PLAYER_STATE_PLAY:
		if (pause_flag)
165
			pc_pause();
166
		break;
167

168 169
	case PLAYER_STATE_PAUSE:
		if (!pause_flag)
170
			pc_pause();
171 172 173 174
		break;
	}
}

175 176
void
pc_get_status(struct player_status *status)
177
{
178 179
	player_command(PLAYER_COMMAND_REFRESH);

180
	status->state = pc.state;
181

182 183 184 185 186 187
	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;
	}
188 189
}

190 191
enum player_state
pc_get_state(void)
192 193 194 195
{
	return pc.state;
}

196 197
void
pc_clear_error(void)
198
{
199 200
	pc.error = PLAYER_ERROR_NOERROR;
	pc.errored_song = NULL;
201 202
}

203 204
enum player_error
pc_get_error(void)
205 206 207 208
{
	return pc.error;
}

209
static char *
210 211
pc_errored_song_uri(void)
{
212
	return song_get_uri(pc.errored_song);
213 214
}

215 216
char *
pc_get_error_message(void)
217
{
218
	char *error;
219 220
	char *uri;

221
	switch (pc.error) {
222
	case PLAYER_ERROR_NOERROR:
223
		return NULL;
224

225
	case PLAYER_ERROR_FILENOTFOUND:
226
		uri = pc_errored_song_uri();
227
		error = g_strdup_printf("file \"%s\" does not exist or is inaccessible", uri);
228
		g_free(uri);
229
		return error;
230

231
	case PLAYER_ERROR_FILE:
232
		uri = pc_errored_song_uri();
233
		error = g_strdup_printf("problems decoding \"%s\"", uri);
234
		g_free(uri);
235
		return error;
236

237
	case PLAYER_ERROR_AUDIO:
238
		return g_strdup("problems opening audio device");
239

240
	case PLAYER_ERROR_SYSTEM:
241
		return g_strdup("system error occured");
242

243
	case PLAYER_ERROR_UNKTYPE:
244
		uri = pc_errored_song_uri();
245
		error = g_strdup_printf("file type of \"%s\" is unknown", uri);
246
		g_free(uri);
247
		return error;
248
	}
249 250 251

	assert(false);
	return NULL;
252 253
}

254
void
255
pc_enqueue_song(struct song *song)
256
{
257
	assert(song != NULL);
258

259
	player_lock();
260 261
	assert(pc.next_song == NULL);

262
	pc.next_song = song;
263 264
	player_command_locked(PLAYER_COMMAND_QUEUE);
	player_unlock();
265 266
}

267 268
bool
pc_seek(struct song *song, float seek_time)
269 270 271 272
{
	assert(song != NULL);

	if (pc.state == PLAYER_STATE_STOP)
273
		return false;
274

275
	player_lock();
276
	pc.next_song = song;
277
	pc.seek_where = seek_time;
278 279
	player_command_locked(PLAYER_COMMAND_SEEK);
	player_unlock();
280

281 282
	assert(pc.next_song == NULL);

283
	idle_add(IDLE_PLAYER);
284

285
	return true;
286 287
}

288 289
float
pc_get_cross_fade(void)
290
{
Max Kellermann's avatar
Max Kellermann committed
291
	return pc.cross_fade_seconds;
292 293
}

294 295
void
pc_set_cross_fade(float cross_fade_seconds)
296
{
297 298 299
	if (cross_fade_seconds < 0)
		cross_fade_seconds = 0;
	pc.cross_fade_seconds = cross_fade_seconds;
300 301

	idle_add(IDLE_OPTIONS);
302 303
}

304 305
double
pc_get_total_play_time(void)
306
{
Max Kellermann's avatar
Max Kellermann committed
307
	return pc.total_play_time;
308
}