Control.cxx 4.55 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2015 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 "Control.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(PlayerListener &_listener,
			     MultipleOutputs &_outputs,
31
			     unsigned _buffer_chunks,
32
			     unsigned _buffered_before_play)
33
	:listener(_listener), outputs(_outputs),
34
	 buffer_chunks(_buffer_chunks),
35
	 buffered_before_play(_buffered_before_play),
36 37 38
	 command(PlayerCommand::NONE),
	 state(PlayerState::STOP),
	 error_type(PlayerError::NONE),
39
	 tagged_song(nullptr),
40
	 next_song(nullptr),
41 42
	 total_play_time(0),
	 border_pause(false)
43 44 45
{
}

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

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

57
	Lock();
58

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

62
	assert(next_song == nullptr);
63

64
	EnqueueSongLocked(song);
65

66
	assert(next_song == nullptr);
67

68
	Unlock();
69 70
}

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

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

	idle_add(IDLE_PLAYER);
85 86
}

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

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

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

	idle_add(IDLE_PLAYER);
102 103
}

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

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

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

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

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

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

141
	Unlock();
142 143
}

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

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

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

160 161
	status.state = state;

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

169 170 171
	Unlock();

	return status;
172 173
}

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

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

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

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

194
	Unlock();
195 196
}

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

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

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

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

223
bool
224
PlayerControl::Seek(DetachedSong *song, SongTime t)
225
{
226
	assert(song != nullptr);
227

228
	Lock();
229

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

236
	assert(next_song == nullptr);
237

238
	idle_add(IDLE_PLAYER);
239

240
	return true;
241 242
}

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

	idle_add(IDLE_OPTIONS);
251 252
}

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

	idle_add(IDLE_OPTIONS);
}

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

	idle_add(IDLE_OPTIONS);
}