input_stream.c 5.13 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2011 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
 */

Max Kellermann's avatar
Max Kellermann committed
20
#include "config.h"
21 22
#include "input_stream.h"
#include "input_registry.h"
23
#include "input_plugin.h"
24
#include "input/rewind_input_plugin.h"
25
#include "uri.h"
26

27
#include <glib.h>
28
#include <assert.h>
29

30 31 32 33 34 35
static inline GQuark
input_quark(void)
{
	return g_quark_from_static_string("input");
}

36
struct input_stream *
37 38 39
input_stream_open(const char *url,
		  GMutex *mutex, GCond *cond,
		  GError **error_r)
Avuton Olrich's avatar
Avuton Olrich committed
40
{
41 42
	GError *error = NULL;

43
	assert(mutex != NULL);
44 45
	assert(error_r == NULL || *error_r == NULL);

46
	input_plugins_for_each_enabled(plugin) {
47
		struct input_stream *is;
Max Kellermann's avatar
Max Kellermann committed
48

49
		is = plugin->open(url, mutex, cond, &error);
50
		if (is != NULL) {
51 52 53 54
			assert(is->plugin != NULL);
			assert(is->plugin->close != NULL);
			assert(is->plugin->read != NULL);
			assert(is->plugin->eof != NULL);
55
			assert(!is->seekable || is->plugin->seek != NULL);
56

57
			is = input_rewind_open(is);
58

59
			return is;
60 61
		} else if (error != NULL) {
			g_propagate_error(error_r, error);
62
			return NULL;
63 64
		}
	}
65

66
	g_set_error(error_r, input_quark(), 0, "Unrecognized URI");
67
	return NULL;
68 69
}

70 71 72 73 74 75 76 77 78 79
bool
input_stream_check(struct input_stream *is, GError **error_r)
{
	assert(is != NULL);
	assert(is->plugin != NULL);

	return is->plugin->check == NULL ||
		is->plugin->check(is, error_r);
}

80 81 82 83 84 85 86 87 88 89
void
input_stream_update(struct input_stream *is)
{
	assert(is != NULL);
	assert(is->plugin != NULL);

	if (is->plugin->update != NULL)
		is->plugin->update(is);
}

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
void
input_stream_wait_ready(struct input_stream *is)
{
	assert(is != NULL);
	assert(is->mutex != NULL);
	assert(is->cond != NULL);

	while (true) {
		input_stream_update(is);
		if (is->ready)
			break;

		g_cond_wait(is->cond, is->mutex);
	}
}

void
input_stream_lock_wait_ready(struct input_stream *is)
{
	assert(is != NULL);
	assert(is->mutex != NULL);
	assert(is->cond != NULL);

	g_mutex_lock(is->mutex);
	input_stream_wait_ready(is);
	g_mutex_unlock(is->mutex);
}

118 119 120 121 122 123
bool
input_stream_cheap_seeking(const struct input_stream *is)
{
	return is->seekable && (is->uri == NULL || !uri_has_scheme(is->uri));
}

124
bool
125 126
input_stream_seek(struct input_stream *is, goffset offset, int whence,
		  GError **error_r)
Avuton Olrich's avatar
Avuton Olrich committed
127
{
128 129 130
	assert(is != NULL);
	assert(is->plugin != NULL);

131 132 133
	if (is->plugin->seek == NULL)
		return false;

134
	return is->plugin->seek(is, offset, whence, error_r);
135 136
}

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
bool
input_stream_lock_seek(struct input_stream *is, goffset offset, int whence,
		       GError **error_r)
{
	assert(is != NULL);
	assert(is->plugin != NULL);

	if (is->plugin->seek == NULL)
		return false;

	if (is->mutex == NULL)
		/* no locking */
		return input_stream_seek(is, offset, whence, error_r);

	g_mutex_lock(is->mutex);
	bool success = input_stream_seek(is, offset, whence, error_r);
	g_mutex_unlock(is->mutex);
	return success;
}

157 158 159 160
struct tag *
input_stream_tag(struct input_stream *is)
{
	assert(is != NULL);
161
	assert(is->plugin != NULL);
162 163 164 165 166 167

	return is->plugin->tag != NULL
		? is->plugin->tag(is)
		: NULL;
}

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
struct tag *
input_stream_lock_tag(struct input_stream *is)
{
	assert(is != NULL);
	assert(is->plugin != NULL);

	if (is->plugin->tag == NULL)
		return false;

	if (is->mutex == NULL)
		/* no locking */
		return input_stream_tag(is);

	g_mutex_lock(is->mutex);
	struct tag *tag = input_stream_tag(is);
	g_mutex_unlock(is->mutex);
	return tag;
}

bool
input_stream_available(struct input_stream *is)
{
	assert(is != NULL);
	assert(is->plugin != NULL);

	return is->plugin->available != NULL
		? is->plugin->available(is)
		: true;
}

198
size_t
199 200
input_stream_read(struct input_stream *is, void *ptr, size_t size,
		  GError **error_r)
201
{
202 203 204
	assert(ptr != NULL);
	assert(size > 0);

205
	return is->plugin->read(is, ptr, size, error_r);
206 207
}

208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
size_t
input_stream_lock_read(struct input_stream *is, void *ptr, size_t size,
		       GError **error_r)
{
	assert(ptr != NULL);
	assert(size > 0);

	if (is->mutex == NULL)
		/* no locking */
		return input_stream_read(is, ptr, size, error_r);

	g_mutex_lock(is->mutex);
	size_t nbytes = input_stream_read(is, ptr, size, error_r);
	g_mutex_unlock(is->mutex);
	return nbytes;
}

225
void input_stream_close(struct input_stream *is)
Avuton Olrich's avatar
Avuton Olrich committed
226
{
227
	is->plugin->close(is);
228
}
229

230
bool input_stream_eof(struct input_stream *is)
Avuton Olrich's avatar
Avuton Olrich committed
231
{
232
	return is->plugin->eof(is);
233
}
234

235 236
bool
input_stream_lock_eof(struct input_stream *is)
Avuton Olrich's avatar
Avuton Olrich committed
237
{
238 239 240 241 242 243
	assert(is != NULL);
	assert(is->plugin != NULL);

	if (is->mutex == NULL)
		/* no locking */
		return input_stream_eof(is);
244

245 246 247 248
	g_mutex_lock(is->mutex);
	bool eof = input_stream_eof(is);
	g_mutex_unlock(is->mutex);
	return eof;
249
}
250