File: mpdclient.hxx

package info (click to toggle)
ncmpc 0.33-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 1,976 kB
  • sloc: cpp: 10,895; python: 133; makefile: 39; ruby: 28; sh: 11
file content (314 lines) | stat: -rw-r--r-- 6,507 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
#ifndef MPDCLIENT_H
#define MPDCLIENT_H

#include "config.h"
#include "Queue.hxx"
#include "gidle.hxx"
#include "util/Compiler.h"
#include "AsioServiceFwd.hxx"

#ifdef ENABLE_ASYNC_CONNECT
#include "aconnect.hxx"
#endif

#include <mpd/client.h>

#include <boost/asio/steady_timer.hpp>

#include <string>

struct AsyncMpdConnect;
struct MpdQueue;
class MpdIdleSource;
class FileList;

struct mpdclient final
	: MpdIdleHandler
#ifdef ENABLE_ASYNC_CONNECT
	, AsyncMpdConnectHandler
#endif
{
#ifdef ENABLE_ASYNC_CONNECT
	/**
	 * These settings are used to connect to MPD asynchronously.
	 */
	struct mpd_settings *settings;

#ifndef _WIN32
	/**
	 * A second set of settings, just in case #settings did not
	 * work.  This is only used if #settings refers to a local
	 * socket path, and this one is supposed to be a fallback to
	 * IP on the default port (6600).
	 */
	struct mpd_settings *settings2;
#endif

#else
	const char *host;
	unsigned port;
#endif

	const unsigned timeout_ms;

	const char *const password;

	/* playlist */
	MpdQueue playlist;

#ifdef ENABLE_ASYNC_CONNECT
	AsyncMpdConnect *async_connect = nullptr;
#endif

	struct mpd_connection *connection = nullptr;

	/**
	 * Tracks idle events.  It is automatically called by
	 * mpdclient_get_connection().
	 */
	MpdIdleSource *source = nullptr;

	struct mpd_status *status = nullptr;
	const struct mpd_song *current_song = nullptr;

	/**
	 * A timer which re-enters MPD idle mode before the next main
	 * loop iteration.
	 */
	boost::asio::steady_timer enter_idle_timer;

	/**
	 * This attribute is incremented whenever the connection changes
	 * (i.e. on disconnection and (re-)connection).
	 */
	unsigned connection_id = 0;

	int volume = -1;

	/**
	 * A bit mask of idle events occurred since the last update.
	 */
	unsigned events = 0;

	enum mpd_state state = MPD_STATE_UNKNOWN;

#if defined(ENABLE_ASYNC_CONNECT) && !defined(_WIN32)
	bool connecting2;
#endif

	/**
	 * This attribute is true when the connection is currently in
	 * "idle" mode, and the #mpd_glib_source waits for an event.
	 */
	bool idle = false;

	/**
	 * Is MPD currently playing?
	 */
	bool playing = false;

	/**
	 * Is MPD currently playing or paused?
	 */
	bool playing_or_paused = false;

	mpdclient(boost::asio::io_service &io_service,
		  const char *host, unsigned port,
		  unsigned _timeout_ms, const char *_password);

	~mpdclient() {
		Disconnect();

#ifdef ENABLE_ASYNC_CONNECT
		mpd_settings_free(settings);

#ifndef _WIN32
		if (settings2 != nullptr)
			mpd_settings_free(settings2);
#endif
#endif
	}

	auto &get_io_service() noexcept {
		return enter_idle_timer.get_io_service();
	}

#ifdef ENABLE_ASYNC_CONNECT

	const struct mpd_settings &GetSettings() const noexcept {
#ifndef _WIN32
		if (connecting2)
			return *settings2;
#endif

		return *settings;
	}

#endif

	/**
	 * Determine a human-readable "name" of the settings currently used to
	 * connect to MPD.
	 *
	 * @return an allocated string that needs to be freed (with g_free())
	 * by the caller
	 */
	std::string GetSettingsName() const;

	bool IsConnected() const {
		return connection != nullptr;
	}

	/**
	 * Is this object "dead"?  i.e. not connected and not
	 * currently doing anything to connect.
	 */
	gcc_pure
	bool IsDead() const {
		return connection == nullptr
#ifdef ENABLE_ASYNC_CONNECT
			&& async_connect == nullptr
#endif
			;
	}

	gcc_pure
	int GetCurrentSongId() const noexcept {
		return status != nullptr
			? mpd_status_get_song_id(status)
			: -1;
	}

	gcc_pure
	int GetCurrentSongPos() const noexcept {
		return status != nullptr
			? mpd_status_get_song_pos(status)
			: -1;
	}

	/**
	 * Returns the song that is "current".  This can be valid even
	 * if MPD is not playing.
	 */
	gcc_pure
	const struct mpd_song *GetCurrentSong() const {
		return current_song;
	}

	gcc_pure
	int GetPlayingSongId() const noexcept {
		return playing_or_paused
			? GetCurrentSongId()
			: -1;
	}

	/**
	 * Returns the song that is currently being played (or
	 * paused).
	 */
	gcc_pure
	const struct mpd_song *GetPlayingSong() const {
		return playing_or_paused
			? GetCurrentSong()
			: nullptr;
	}

	void Connect();

	void Disconnect();

	bool HandleError();

	struct mpd_connection *GetConnection();

	bool FinishCommand() {
		return mpd_response_finish(connection) || HandleError();
	}

	bool Update();

	bool OnConnected(struct mpd_connection *_connection) noexcept;

	const struct mpd_status *ReceiveStatus() noexcept;

	bool RunVolume(unsigned new_volume) noexcept;
	bool RunVolumeUp() noexcept;
	bool RunVolumeDown() noexcept;

	bool RunClearQueue() noexcept;
	bool RunAdd(const struct mpd_song &song) noexcept;
	bool RunDelete(unsigned pos) noexcept;
	bool RunDeleteRange(unsigned start, unsigned end) noexcept;
	bool RunMove(unsigned dest, unsigned src) noexcept;

private:
#ifdef ENABLE_ASYNC_CONNECT
	void StartConnect(const struct mpd_settings &s) noexcept;
#endif

	void InvokeErrorCallback() noexcept;

	bool UpdateQueue();
	bool UpdateQueueChanges();

	void ClearStatus() noexcept;

	void ScheduleEnterIdle() noexcept;
	void CancelEnterIdle() noexcept {
		enter_idle_timer.cancel();
	}
	void OnEnterIdleTimer(const boost::system::error_code &error) noexcept;

#ifdef ENABLE_ASYNC_CONNECT
	/* virtual methods from AsyncMpdConnectHandler */
	void OnAsyncMpdConnect(struct mpd_connection *c) noexcept override;
	void OnAsyncMpdConnectError(const char *message) noexcept override;
#endif

	/* virtual methods from MpdIdleHandler */
	void OnIdle(unsigned events) noexcept override;
	void OnIdleError(enum mpd_error error,
			 enum mpd_server_error server_error,
			 const char *message) noexcept override;
};

enum {
	/**
	 * all idle events the version of libmpdclient, ncmpc is compiled
	 * against, supports
	 */
	MPD_IDLE_ALL = MPD_IDLE_DATABASE
		| MPD_IDLE_STORED_PLAYLIST
		| MPD_IDLE_QUEUE
		| MPD_IDLE_PLAYER
		| MPD_IDLE_MIXER
		| MPD_IDLE_OUTPUT
		| MPD_IDLE_OPTIONS
		| MPD_IDLE_UPDATE
		| MPD_IDLE_STICKER
		| MPD_IDLE_SUBSCRIPTION
		| MPD_IDLE_MESSAGE
};

/*** MPD Commands  **********************************************************/

bool
mpdclient_cmd_crop(struct mpdclient *c);

bool
mpdclient_cmd_clear(struct mpdclient *c);

bool
mpdclient_cmd_add_path(struct mpdclient *c, const char *path);

bool
mpdclient_cmd_subscribe(struct mpdclient *c, const char *channel);

bool
mpdclient_cmd_unsubscribe(struct mpdclient *c, const char *channel);

bool
mpdclient_cmd_send_message(struct mpdclient *c, const char *channel,
			   const char *text);

#endif