InputStream.hxx 6.71 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2014 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * 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.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef MPD_INPUT_STREAM_HXX
#define MPD_INPUT_STREAM_HXX

#include "check.h"
24
#include "thread/Mutex.hxx"
25
#include "Compiler.h"
26

27
#include <string>
28

29
#include <assert.h>
30
#include <stdint.h>
31

32
class Cond;
33 34
class Error;
struct Tag;
35
struct InputPlugin;
36

37
struct InputStream {
38 39
	typedef int64_t offset_type;

40 41 42
	/**
	 * the plugin which implements this input stream
	 */
43
	const InputPlugin &plugin;
44 45

	/**
46
	 * The absolute URI which was used to open this stream.
47
	 */
48
	std::string uri;
49 50 51 52 53 54 55 56 57

	/**
	 * A mutex that protects the mutable attributes of this object
	 * and its implementation.  It must be locked before calling
	 * any of the public methods.
	 *
	 * This object is allocated by the client, and the client is
	 * responsible for freeing it.
	 */
58
	Mutex &mutex;
59 60 61 62

	/**
	 * A cond that gets signalled when the state of this object
	 * changes from the I/O thread.  The client of this object may
63
	 * wait on it.  Optional, may be nullptr.
64 65 66 67
	 *
	 * This object is allocated by the client, and the client is
	 * responsible for freeing it.
	 */
68
	Cond &cond;
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83

	/**
	 * indicates whether the stream is ready for reading and
	 * whether the other attributes in this struct are valid
	 */
	bool ready;

	/**
	 * if true, then the stream is fully seekable
	 */
	bool seekable;

	/**
	 * the size of the resource, or -1 if unknown
	 */
84
	offset_type size;
85 86 87 88

	/**
	 * the current offset within the stream
	 */
89
	offset_type offset;
90 91

	/**
92
	 * the MIME content type of the resource, or empty if unknown.
93
	 */
94
	std::string mime;
95

96 97
	InputStream(const InputPlugin &_plugin,
		    const char *_uri, Mutex &_mutex, Cond &_cond)
98
		:plugin(_plugin), uri(_uri),
99
		 mutex(_mutex), cond(_cond),
100
		 ready(false), seekable(false),
101
		 size(-1), offset(0) {
102
		assert(_uri != nullptr);
103
	}
104

105 106 107 108 109 110 111
	/**
	 * Opens a new input stream.  You may not access it until the "ready"
	 * flag is set.
	 *
	 * @param mutex a mutex that is used to protect this object; must be
	 * locked before calling any of the public methods
	 * @param cond a cond that gets signalled when the state of
112
	 * this object changes; may be nullptr if the caller doesn't want to get
113
	 * notifications
114
	 * @return an #InputStream object on success, nullptr on error
115 116 117
	 */
	gcc_nonnull_all
	gcc_malloc
118 119
	static InputStream *Open(const char *uri, Mutex &mutex, Cond &cond,
				 Error &error);
120

121 122 123 124 125 126 127 128 129
	/**
	 * Just like Open(), but waits for the stream to become ready.
	 * It is a wrapper for Open(), WaitReady() and Check().
	 */
	gcc_malloc gcc_nonnull_all
	static InputStream *OpenReady(const char *uri,
				      Mutex &mutex, Cond &cond,
				      Error &error);

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
	/**
	 * Close the input stream and free resources.
	 *
	 * The caller must not lock the mutex.
	 */
	void Close();

	void Lock() {
		mutex.lock();
	}

	void Unlock() {
		mutex.unlock();
	}

	/**
	 * Check for errors that may have occurred in the I/O thread.
	 *
	 * @return false on error
	 */
	bool Check(Error &error);

	/**
	 * Update the public attributes.  Call before accessing attributes
	 * such as "ready" or "offset".
	 */
	void Update();

	/**
	 * Wait until the stream becomes ready.
	 *
	 * The caller must lock the mutex.
	 */
	void WaitReady();

	/**
	 * Wrapper for WaitReady() which locks and unlocks the mutex;
	 * the caller must not be holding it already.
	 */
	void LockWaitReady();

	gcc_pure
	const char *GetMimeType() const {
		assert(ready);

		return mime.empty() ? nullptr : mime.c_str();
	}

	gcc_nonnull_all
	void OverrideMimeType(const char *_mime) {
		assert(ready);

		mime = _mime;
	}

	gcc_pure
186
	offset_type GetSize() const {
187 188 189 190 191 192
		assert(ready);

		return size;
	}

	gcc_pure
193
	offset_type GetOffset() const {
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
		assert(ready);

		return offset;
	}

	gcc_pure
	bool IsSeekable() const {
		assert(ready);

		return seekable;
	}

	/**
	 * Determines whether seeking is cheap.  This is true for local files.
	 */
	gcc_pure
	bool CheapSeeking() const;

	/**
	 * Seeks to the specified position in the stream.  This will most
	 * likely fail if the "seekable" flag is false.
	 *
	 * The caller must lock the mutex.
	 *
	 * @param offset the relative offset
	 * @param whence the base of the seek, one of SEEK_SET, SEEK_CUR, SEEK_END
	 */
221
	bool Seek(offset_type offset, int whence, Error &error);
222 223 224 225 226

	/**
	 * Wrapper for Seek() which locks and unlocks the mutex; the
	 * caller must not be holding it already.
	 */
227
	bool LockSeek(offset_type offset, int whence, Error &error);
228

229 230 231 232 233 234 235
	/**
	 * Rewind to the beginning of the stream.  This is a wrapper
	 * for Seek(0, SEEK_SET, error).
	 */
	bool Rewind(Error &error);
	bool LockRewind(Error &error);

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
	/**
	 * Returns true if the stream has reached end-of-file.
	 *
	 * The caller must lock the mutex.
	 */
	gcc_pure
	bool IsEOF();

	/**
	 * Wrapper for IsEOF() which locks and unlocks the mutex; the
	 * caller must not be holding it already.
	 */
	gcc_pure
	bool LockIsEOF();

	/**
	 * Reads the tag from the stream.
	 *
	 * The caller must lock the mutex.
	 *
	 * @return a tag object which must be freed by the caller, or
	 * nullptr if the tag has not changed since the last call
	 */
	gcc_malloc
	Tag *ReadTag();

	/**
	 * Wrapper for ReadTag() which locks and unlocks the mutex;
	 * the caller must not be holding it already.
	 */
	gcc_malloc
	Tag *LockReadTag();

	/**
	 * Returns true if the next read operation will not block: either data
	 * is available, or end-of-stream has been reached, or an error has
	 * occurred.
	 *
	 * The caller must lock the mutex.
	 */
	gcc_pure
	bool IsAvailable();

	/**
	 * Reads data from the stream into the caller-supplied buffer.
	 * Returns 0 on error or eof (check with IsEOF()).
	 *
	 * The caller must lock the mutex.
	 *
285
	 * @param is the InputStream object
286 287 288 289 290 291 292 293 294 295 296 297 298 299
	 * @param ptr the buffer to read into
	 * @param size the maximum number of bytes to read
	 * @return the number of bytes read
	 */
	gcc_nonnull_all
	size_t Read(void *ptr, size_t size, Error &error);

	/**
	 * Wrapper for Read() which locks and unlocks the mutex;
	 * the caller must not be holding it already.
	 */
	gcc_nonnull_all
	size_t LockRead(void *ptr, size_t size, Error &error);
};
300 301

#endif