PlayerControl.cxx 4.52 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2014 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 "PlayerControl.hxx"
Max Kellermann's avatar
Max Kellermann committed
22
#include "Idle.hxx"
23
#include "DetachedSong.hxx"
24

25
#include <algorithm>
26

Max Kellermann's avatar
Max Kellermann committed
27
#include <assert.h>
28

29 30
PlayerControl::PlayerControl(MultipleOutputs &_outputs,
			     unsigned _buffer_chunks,
31
			     unsigned _buffered_before_play)
32 33
	:outputs(_outputs),
	 buffer_chunks(_buffer_chunks),
34
	 buffered_before_play(_buffered_before_play),
35 36 37
	 command(PlayerCommand::NONE),
	 state(PlayerState::STOP),
	 error_type(PlayerError::NONE),
38
	 tagged_song(nullptr),
39
	 next_song(nullptr),
40 41
	 total_play_time(0),
	 border_pause(false)
42 43 44
{
}

45
PlayerControl::~PlayerControl()
46
{
47 48
	delete next_song;
	delete tagged_song;
49 50
}

51
void
52
PlayerControl::Play(DetachedSong *song)
53
{
54
	assert(song != nullptr);
55

56
	Lock();
57

58 59
	if (state != PlayerState::STOP)
		SynchronousCommand(PlayerCommand::STOP);
60

61
	assert(next_song == nullptr);
62

63
	EnqueueSongLocked(song);
64

65
	assert(next_song == nullptr);
66

67
	Unlock();
68 69
}

70
void
71
PlayerControl::Cancel()
72
{
73
	LockSynchronousCommand(PlayerCommand::CANCEL);
74
	assert(next_song == nullptr);
75
}
76

77
void
78
PlayerControl::Stop()
79
{
80
	LockSynchronousCommand(PlayerCommand::CLOSE_AUDIO);
81
	assert(next_song == nullptr);
82 83

	idle_add(IDLE_PLAYER);
84 85
}

86
void
87
PlayerControl::UpdateAudio()
88
{
89
	LockSynchronousCommand(PlayerCommand::UPDATE_AUDIO);
90 91
}

92
void
93
PlayerControl::Kill()
94
{
95
	assert(thread.IsDefined());
96

97
	LockSynchronousCommand(PlayerCommand::EXIT);
98
	thread.Join();
99 100

	idle_add(IDLE_PLAYER);
101 102
}

103
void
104
PlayerControl::PauseLocked()
105
{
106 107
	if (state != PlayerState::STOP) {
		SynchronousCommand(PlayerCommand::PAUSE);
108 109 110 111
		idle_add(IDLE_PLAYER);
	}
}

112
void
113
PlayerControl::Pause()
114
{
115 116 117
	Lock();
	PauseLocked();
	Unlock();
118 119
}

120
void
121
PlayerControl::SetPause(bool pause_flag)
122
{
123
	Lock();
124

125
	switch (state) {
126
	case PlayerState::STOP:
127 128
		break;

129
	case PlayerState::PLAY:
130
		if (pause_flag)
131
			PauseLocked();
132
		break;
133

134
	case PlayerState::PAUSE:
135
		if (!pause_flag)
136
			PauseLocked();
137 138
		break;
	}
139

140
	Unlock();
141 142
}

143
void
144
PlayerControl::SetBorderPause(bool _border_pause)
145
{
146 147 148
	Lock();
	border_pause = _border_pause;
	Unlock();
149 150
}

151
player_status
152
PlayerControl::GetStatus()
153
{
154
	player_status status;
155

156
	Lock();
157
	SynchronousCommand(PlayerCommand::REFRESH);
158

159 160
	status.state = state;

161
	if (state != PlayerState::STOP) {
162 163 164 165
		status.bit_rate = bit_rate;
		status.audio_format = audio_format;
		status.total_time = total_time;
		status.elapsed_time = elapsed_time;
166
	}
167

168 169 170
	Unlock();

	return status;
171 172
}

173
void
174
PlayerControl::SetError(PlayerError type, Error &&_error)
175
{
176
	assert(type != PlayerError::NONE);
177
	assert(_error.IsDefined());
178

179
	error_type = type;
180
	error = std::move(_error);
181 182
}

183
void
184
PlayerControl::ClearError()
185
{
186
	Lock();
187

188 189
	if (error_type != PlayerError::NONE) {
	    error_type = PlayerError::NONE;
190
	    error.Clear();
191 192
	}

193
	Unlock();
194 195
}

196
void
197
PlayerControl::LockSetTaggedSong(const DetachedSong &song)
198 199
{
	Lock();
200 201
	delete tagged_song;
	tagged_song = new DetachedSong(song);
202 203 204 205
	Unlock();
}

void
206
PlayerControl::ClearTaggedSong()
207
{
208 209
	delete tagged_song;
	tagged_song = nullptr;
210 211
}

212
void
213
PlayerControl::EnqueueSong(DetachedSong *song)
214
{
215
	assert(song != nullptr);
216

217
	Lock();
218
	EnqueueSongLocked(song);
219
	Unlock();
220 221
}

222
bool
223
PlayerControl::Seek(DetachedSong *song, float seek_time)
224
{
225
	assert(song != nullptr);
226

227
	Lock();
228

229
	delete next_song;
230 231
	next_song = song;
	seek_where = seek_time;
232
	SynchronousCommand(PlayerCommand::SEEK);
233
	Unlock();
234

235
	assert(next_song == nullptr);
236

237
	idle_add(IDLE_PLAYER);
238

239
	return true;
240 241
}

242
void
243
PlayerControl::SetCrossFade(float _cross_fade_seconds)
244
{
245 246
	if (_cross_fade_seconds < 0)
		_cross_fade_seconds = 0;
247
	cross_fade.duration = _cross_fade_seconds;
248 249

	idle_add(IDLE_OPTIONS);
250 251
}

252
void
253
PlayerControl::SetMixRampDb(float _mixramp_db)
254
{
255
	cross_fade.mixramp_db = _mixramp_db;
256 257 258 259 260

	idle_add(IDLE_OPTIONS);
}

void
261
PlayerControl::SetMixRampDelay(float _mixramp_delay_seconds)
262
{
263
	cross_fade.mixramp_delay = _mixramp_delay_seconds;
264 265 266

	idle_add(IDLE_OPTIONS);
}