player_control.c 5.06 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/* the Music Player Daemon (MPD)
 * Copyright (C) 2008 Max Kellermann <max@duempel.org>
 * This project's homepage is: http://www.musicpd.org
 *
 * 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.
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

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

Max Kellermann's avatar
Max Kellermann committed
28 29 30
#include <assert.h>
#include <stdio.h>

31
struct player_control pc;
32

33 34 35 36 37 38 39
void pc_init(unsigned int buffered_before_play)
{
	pc.buffered_before_play = buffered_before_play;
	notify_init(&pc.notify);
	pc.command = PLAYER_COMMAND_NONE;
	pc.error = PLAYER_ERROR_NOERROR;
	pc.state = PLAYER_STATE_STOP;
Max Kellermann's avatar
Max Kellermann committed
40
	pc.cross_fade_seconds = 0;
41
	pc.software_volume = PCM_VOLUME_1;
42 43
}

44 45 46 47 48
void pc_deinit(void)
{
	notify_deinit(&pc.notify);
}

49 50 51
void
pc_song_deleted(const struct song *song)
{
52 53
	if (pc.errored_song == song) {
		pc.error = PLAYER_ERROR_NOERROR;
54
		pc.errored_song = NULL;
55
	}
56 57
}

58 59 60 61 62
static void player_command(enum player_command cmd)
{
	pc.command = cmd;
	while (pc.command != PLAYER_COMMAND_NONE) {
		notify_signal(&pc.notify);
63
		notify_wait(&main_notify);
64 65 66
	}
}

67 68
void
playerPlay(struct song *song)
69
{
70
	assert(song != NULL);
71 72 73 74

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

75
	pc.next_song = song;
76
	player_command(PLAYER_COMMAND_PLAY);
77 78

	idle_add(IDLE_PLAYER);
79 80
}

81
void pc_cancel(void)
82
{
83 84
	player_command(PLAYER_COMMAND_CANCEL);
}
85

86 87
void playerWait(void)
{
88
	player_command(PLAYER_COMMAND_CLOSE_AUDIO);
89 90

	idle_add(IDLE_PLAYER);
91 92 93 94
}

void playerKill(void)
{
95 96
	assert(pc.thread != NULL);

97
	player_command(PLAYER_COMMAND_EXIT);
98 99
	g_thread_join(pc.thread);
	pc.thread = NULL;
100 101

	idle_add(IDLE_PLAYER);
102 103 104 105
}

void playerPause(void)
{
106
	if (pc.state != PLAYER_STATE_STOP) {
107
		player_command(PLAYER_COMMAND_PAUSE);
108 109
		idle_add(IDLE_PLAYER);
	}
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
}

void playerSetPause(int pause_flag)
{
	switch (pc.state) {
	case PLAYER_STATE_STOP:
		break;

	case PLAYER_STATE_PLAY:
		if (pause_flag)
			playerPause();
		break;
	case PLAYER_STATE_PAUSE:
		if (!pause_flag)
			playerPause();
		break;
	}
}

int getPlayerElapsedTime(void)
{
Max Kellermann's avatar
Max Kellermann committed
131
	return (int)(pc.elapsed_time + 0.5);
132 133 134 135
}

unsigned long getPlayerBitRate(void)
{
Max Kellermann's avatar
Max Kellermann committed
136
	return pc.bit_rate;
137 138 139 140
}

int getPlayerTotalTime(void)
{
Max Kellermann's avatar
Max Kellermann committed
141
	return (int)(pc.total_time + 0.5);
142 143 144 145 146 147 148 149 150 151 152 153
}

enum player_state getPlayerState(void)
{
	return pc.state;
}

void clearPlayerError(void)
{
	pc.error = 0;
}

154
enum player_error getPlayerError(void)
155 156 157 158
{
	return pc.error;
}

159
static char *
160 161
pc_errored_song_uri(void)
{
162
	return song_get_uri(pc.errored_song);
163 164
}

165 166 167 168 169
char *getPlayerErrorStr(void)
{
	/* static OK here, only one user in main task */
	static char error[MPD_PATH_MAX + 64]; /* still too much */
	static const size_t errorlen = sizeof(error);
170 171
	char *uri;

172 173 174
	*error = '\0'; /* likely */

	switch (pc.error) {
175 176 177
	case PLAYER_ERROR_NOERROR:
		break;

178
	case PLAYER_ERROR_FILENOTFOUND:
179
		uri = pc_errored_song_uri();
180
		snprintf(error, errorlen,
181 182
			 "file \"%s\" does not exist or is inaccessible", uri);
		g_free(uri);
183
		break;
184

185
	case PLAYER_ERROR_FILE:
186 187 188
		uri = pc_errored_song_uri();
		snprintf(error, errorlen, "problems decoding \"%s\"", uri);
		g_free(uri);
189
		break;
190

191 192 193
	case PLAYER_ERROR_AUDIO:
		strcpy(error, "problems opening audio device");
		break;
194

195 196 197
	case PLAYER_ERROR_SYSTEM:
		strcpy(error, "system error occured");
		break;
198

199
	case PLAYER_ERROR_UNKTYPE:
200 201 202 203 204
		uri = pc_errored_song_uri();
		snprintf(error, errorlen,
			 "file type of \"%s\" is unknown", uri);
		g_free(uri);
		break;
205 206 207 208
	}
	return *error ? error : NULL;
}

209 210
void
queueSong(struct song *song)
211
{
212
	assert(song != NULL);
213
	assert(pc.next_song == NULL);
214

215
	pc.next_song = song;
216
	player_command(PLAYER_COMMAND_QUEUE);
217 218
}

219 220
int
playerSeek(struct song *song, float seek_time)
221 222 223 224 225 226
{
	assert(song != NULL);

	if (pc.state == PLAYER_STATE_STOP)
		return -1;

227
	pc.next_song = song;
228 229

	if (pc.error == PLAYER_ERROR_NOERROR) {
Max Kellermann's avatar
Max Kellermann committed
230
		pc.seek_where = seek_time;
231
		player_command(PLAYER_COMMAND_SEEK);
232 233

		idle_add(IDLE_PLAYER);
234 235 236 237 238 239 240
	}

	return 0;
}

float getPlayerCrossFade(void)
{
Max Kellermann's avatar
Max Kellermann committed
241
	return pc.cross_fade_seconds;
242 243 244 245 246 247
}

void setPlayerCrossFade(float crossFadeInSeconds)
{
	if (crossFadeInSeconds < 0)
		crossFadeInSeconds = 0;
Max Kellermann's avatar
Max Kellermann committed
248
	pc.cross_fade_seconds = crossFadeInSeconds;
249 250

	idle_add(IDLE_OPTIONS);
251 252 253 254
}

void setPlayerSoftwareVolume(int volume)
{
255 256 257 258 259
	if (volume > PCM_VOLUME_1)
		volume = PCM_VOLUME_1;
	else if (volume < 0)
		volume = 0;

Max Kellermann's avatar
Max Kellermann committed
260
	pc.software_volume = volume;
261 262 263 264
}

double getPlayerTotalPlayTime(void)
{
Max Kellermann's avatar
Max Kellermann committed
265
	return pc.total_play_time;
266 267 268
}

/* this actually creates a dupe of the current metadata */
269 270
struct song *
playerCurrentDecodeSong(void)
271 272 273
{
	return NULL;
}