player_control.c 7.49 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2011 The Music Player Daemon Project
3
 * 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 "config.h"
21
#include "player_control.h"
22
#include "decoder_control.h"
23 24
#include "path.h"
#include "log.h"
Max Kellermann's avatar
Max Kellermann committed
25
#include "tag.h"
26
#include "song.h"
27
#include "idle.h"
28
#include "pcm_volume.h"
29
#include "main.h"
30

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

35
static void
36
pc_enqueue_song_locked(struct player_control *pc, struct song *song);
37

38 39
struct player_control *
pc_new(unsigned buffer_chunks, unsigned int buffered_before_play)
40
{
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
	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;
57 58
}

59 60
void
pc_free(struct player_control *pc)
61
{
62 63 64
	g_cond_free(pc->cond);
	g_mutex_free(pc->mutex);
	g_free(pc);
65 66 67
}

void
68
player_wait_decoder(struct player_control *pc, struct decoder_control *dc)
69
{
70 71
	assert(pc != NULL);
	assert(dc != NULL);
72
	assert(dc->client_cond == pc->cond);
73

74 75
	/* during this function, the decoder lock is held, because
	   we're waiting for the decoder thread */
76
	g_cond_wait(pc->cond, dc->mutex);
77 78
}

79
void
80
pc_song_deleted(struct player_control *pc, const struct song *song)
81
{
82 83 84
	if (pc->errored_song == song) {
		pc->error = PLAYER_ERROR_NOERROR;
		pc->errored_song = NULL;
85
	}
86 87
}

88
static void
89
player_command_wait_locked(struct player_control *pc)
90
{
91 92
	while (pc->command != PLAYER_COMMAND_NONE)
		g_cond_wait(main_cond, pc->mutex);
93 94 95
}

static void
96
player_command_locked(struct player_control *pc, enum player_command cmd)
97
{
98
	assert(pc->command == PLAYER_COMMAND_NONE);
99

100 101 102
	pc->command = cmd;
	player_signal(pc);
	player_command_wait_locked(pc);
103 104 105
}

static void
106
player_command(struct player_control *pc, enum player_command cmd)
107
{
108 109 110
	player_lock(pc);
	player_command_locked(pc, cmd);
	player_unlock(pc);
111 112
}

113
void
114
pc_play(struct player_control *pc, struct song *song)
115
{
116
	assert(song != NULL);
117

118
	player_lock(pc);
119

120 121
	if (pc->state != PLAYER_STATE_STOP)
		player_command_locked(pc, PLAYER_COMMAND_STOP);
122

123
	assert(pc->next_song == NULL);
124

125
	pc_enqueue_song_locked(pc, song);
126

127
	assert(pc->next_song == NULL);
128

129
	player_unlock(pc);
130

131
	idle_add(IDLE_PLAYER);
132 133
}

134 135
void
pc_cancel(struct player_control *pc)
136
{
137 138
	player_command(pc, PLAYER_COMMAND_CANCEL);
	assert(pc->next_song == NULL);
139
}
140

141
void
142
pc_stop(struct player_control *pc)
143
{
144 145
	player_command(pc, PLAYER_COMMAND_CLOSE_AUDIO);
	assert(pc->next_song == NULL);
146 147

	idle_add(IDLE_PLAYER);
148 149
}

150
void
151
pc_update_audio(struct player_control *pc)
152
{
153
	player_command(pc, PLAYER_COMMAND_UPDATE_AUDIO);
154 155
}

156
void
157
pc_kill(struct player_control *pc)
158
{
159
	assert(pc->thread != NULL);
160

161 162 163
	player_command(pc, PLAYER_COMMAND_EXIT);
	g_thread_join(pc->thread);
	pc->thread = NULL;
164 165

	idle_add(IDLE_PLAYER);
166 167
}

168
void
169
pc_pause(struct player_control *pc)
170
{
171
	player_lock(pc);
172

173 174
	if (pc->state != PLAYER_STATE_STOP) {
		player_command_locked(pc, PLAYER_COMMAND_PAUSE);
175 176 177
		idle_add(IDLE_PLAYER);
	}

178
	player_unlock(pc);
179 180 181
}

static void
182
pc_pause_locked(struct player_control *pc)
183
{
184 185
	if (pc->state != PLAYER_STATE_STOP) {
		player_command_locked(pc, PLAYER_COMMAND_PAUSE);
186 187
		idle_add(IDLE_PLAYER);
	}
188 189
}

190
void
191
pc_set_pause(struct player_control *pc, bool pause_flag)
192
{
193
	player_lock(pc);
194

195
	switch (pc->state) {
196 197 198 199 200
	case PLAYER_STATE_STOP:
		break;

	case PLAYER_STATE_PLAY:
		if (pause_flag)
201
			pc_pause_locked(pc);
202
		break;
203

204 205
	case PLAYER_STATE_PAUSE:
		if (!pause_flag)
206
			pc_pause_locked(pc);
207 208
		break;
	}
209

210
	player_unlock(pc);
211 212
}

213
void
214
pc_get_status(struct player_control *pc, struct player_status *status)
215
{
216 217
	player_lock(pc);
	player_command_locked(pc, PLAYER_COMMAND_REFRESH);
218

219
	status->state = pc->state;
220

221 222 223 224 225
	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;
226
	}
227

228
	player_unlock(pc);
229 230
}

231
enum player_state
232
pc_get_state(struct player_control *pc)
233
{
234
	return pc->state;
235 236
}

237
void
238
pc_clear_error(struct player_control *pc)
239
{
240 241 242 243
	player_lock(pc);
	pc->error = PLAYER_ERROR_NOERROR;
	pc->errored_song = NULL;
	player_unlock(pc);
244 245
}

246
enum player_error
247
pc_get_error(struct player_control *pc)
248
{
249
	return pc->error;
250 251
}

252
static char *
253
pc_errored_song_uri(struct player_control *pc)
254
{
255
	return song_get_uri(pc->errored_song);
256 257
}

258
char *
259
pc_get_error_message(struct player_control *pc)
260
{
261
	char *error;
262 263
	char *uri;

264
	switch (pc->error) {
265
	case PLAYER_ERROR_NOERROR:
266
		return NULL;
267

268
	case PLAYER_ERROR_FILENOTFOUND:
269
		uri = pc_errored_song_uri(pc);
270
		error = g_strdup_printf("file \"%s\" does not exist or is inaccessible", uri);
271
		g_free(uri);
272
		return error;
273

274
	case PLAYER_ERROR_FILE:
275
		uri = pc_errored_song_uri(pc);
276
		error = g_strdup_printf("problems decoding \"%s\"", uri);
277
		g_free(uri);
278
		return error;
279

280
	case PLAYER_ERROR_AUDIO:
281
		return g_strdup("problems opening audio device");
282

283
	case PLAYER_ERROR_SYSTEM:
284
		return g_strdup("system error occured");
285

286
	case PLAYER_ERROR_UNKTYPE:
287
		uri = pc_errored_song_uri(pc);
288
		error = g_strdup_printf("file type of \"%s\" is unknown", uri);
289
		g_free(uri);
290
		return error;
291
	}
292 293 294

	assert(false);
	return NULL;
295 296
}

297
static void
298
pc_enqueue_song_locked(struct player_control *pc, struct song *song)
299
{
300
	assert(song != NULL);
301
	assert(pc->next_song == NULL);
302

303 304
	pc->next_song = song;
	player_command_locked(pc, PLAYER_COMMAND_QUEUE);
305 306 307
}

void
308
pc_enqueue_song(struct player_control *pc, struct song *song)
309 310 311
{
	assert(song != NULL);

312 313 314
	player_lock(pc);
	pc_enqueue_song_locked(pc, song);
	player_unlock(pc);
315 316
}

317
bool
318
pc_seek(struct player_control *pc, struct song *song, float seek_time)
319 320 321
{
	assert(song != NULL);

322
	if (pc->state == PLAYER_STATE_STOP)
323
		return false;
324

325 326 327 328 329
	player_lock(pc);
	pc->next_song = song;
	pc->seek_where = seek_time;
	player_command_locked(pc, PLAYER_COMMAND_SEEK);
	player_unlock(pc);
330

331
	assert(pc->next_song == NULL);
332

333
	idle_add(IDLE_PLAYER);
334

335
	return true;
336 337
}

338
float
339
pc_get_cross_fade(const struct player_control *pc)
340
{
341
	return pc->cross_fade_seconds;
342 343
}

344
void
345
pc_set_cross_fade(struct player_control *pc, float cross_fade_seconds)
346
{
347 348
	if (cross_fade_seconds < 0)
		cross_fade_seconds = 0;
349
	pc->cross_fade_seconds = cross_fade_seconds;
350 351

	idle_add(IDLE_OPTIONS);
352 353
}

354
float
355
pc_get_mixramp_db(const struct player_control *pc)
356
{
357
	return pc->mixramp_db;
358 359 360
}

void
361
pc_set_mixramp_db(struct player_control *pc, float mixramp_db)
362
{
363
	pc->mixramp_db = mixramp_db;
364 365 366 367 368

	idle_add(IDLE_OPTIONS);
}

float
369
pc_get_mixramp_delay(const struct player_control *pc)
370
{
371
	return pc->mixramp_delay_seconds;
372 373 374
}

void
375
pc_set_mixramp_delay(struct player_control *pc, float mixramp_delay_seconds)
376
{
377
	pc->mixramp_delay_seconds = mixramp_delay_seconds;
378 379 380 381

	idle_add(IDLE_OPTIONS);
}

382
double
383
pc_get_total_play_time(const struct player_control *pc)
384
{
385
	return pc->total_play_time;
386
}