示例#1
0
/**
 * This is called at the border between two songs: the audio output
 * has consumed all chunks of the current song, and we should start
 * sending chunks from the next one.
 *
 * The player lock is not held.
 *
 * @return true on success, false on error (playback will be stopped)
 */
static bool
player_song_border(struct player *player)
{
	player->xfade = XFADE_UNKNOWN;

	char *uri = song_get_uri(player->song);
	g_message("played \"%s\"", uri);
	g_free(uri);

	music_pipe_free(player->pipe);
	player->pipe = player->dc->pipe;

	audio_output_all_song_border();

	if (!player_wait_for_decoder(player))
		return false;

	struct player_control *const pc = player->pc;
	player_lock(pc);

	if (pc->border_pause) {
		player->paused = true;
		pc->state = PLAYER_STATE_PAUSE;
	}

	player_unlock(pc);

	return true;
}
示例#2
0
/**
 * The decoder has acknowledged the "START" command (see
 * player_wait_for_decoder()).  This function checks if the decoder
 * initialization has completed yet.
 *
 * The player lock is not held.
 */
static bool
player_check_decoder_startup(struct player *player)
{
	struct player_control *pc = player->pc;
	struct decoder_control *dc = player->dc;

	assert(player->decoder_starting);

	decoder_lock(dc);

	GError *error = dc_get_error(dc);
	if (error != NULL) {
		/* the decoder failed */
		decoder_unlock(dc);

		player_lock(pc);
		pc_set_error(pc, PLAYER_ERROR_DECODER, error);
		player_unlock(pc);

		return false;
	} else if (!decoder_is_starting(dc)) {
		/* the decoder is ready and ok */

		decoder_unlock(dc);

		if (player->output_open &&
		    !audio_output_all_wait(pc, 1))
			/* the output devices havn't finished playing
			   all chunks yet - wait for that */
			return true;

		player_lock(pc);
		pc->total_time = real_song_duration(dc->song, dc->total_time);
		pc->audio_format = dc->in_audio_format;
		player_unlock(pc);

		player->play_audio_format = dc->out_audio_format;
		player->decoder_starting = false;

		if (!player->paused && !player_open_output(player)) {
			char *uri = song_get_uri(dc->song);
			g_warning("problems opening audio device "
				  "while playing \"%s\"", uri);
			g_free(uri);

			return true;
		}

		return true;
	} else {
		/* the decoder is not yet ready; wait
		   some more */
		player_wait_decoder(pc, dc);
		decoder_unlock(dc);

		return true;
	}
}
示例#3
0
GPtrArray *
spl_load(const char *utf8path)
{
	FILE *file;
	GPtrArray *list;
	char buffer[MPD_PATH_MAX];
	char *path_fs;

	if (!spl_valid_name(utf8path))
		return NULL;

	path_fs = map_spl_utf8_to_fs(utf8path);
	if (path_fs == NULL)
		return NULL;

	while (!(file = fopen(path_fs, "r")) && errno == EINTR);
	g_free(path_fs);
	if (file == NULL)
		return NULL;

	list = g_ptr_array_new();

	while (fgets(buffer, sizeof(buffer), file)) {
		char *s = buffer;

		if (*s == PLAYLIST_COMMENT)
			continue;

		g_strchomp(buffer);

		if (!uri_has_scheme(s)) {
			char *path_utf8;
			struct song *song;

			path_utf8 = map_fs_to_utf8(s);
			if (path_utf8 == NULL)
				continue;

			song = db_get_song(path_utf8);
			g_free(path_utf8);
			if (song == NULL)
				continue;

			s = song_get_uri(song);
		} else
			s = g_strdup(s);

		g_ptr_array_add(list, s);

		if (list->len >= playlist_max_length)
			break;
	}

	while (fclose(file) && errno == EINTR);
	return list;
}
char *
sticker_song_get_value(const struct song *song, const char *name)
{
	char *uri, *value;

	assert(song != NULL);
	assert(song_in_database(song));

	uri = song_get_uri(song);
	value = sticker_load_value("song", uri, name);
	g_free(uri);

	return value;
}
struct sticker *
sticker_song_get(const struct song *song)
{
	char *uri;
	struct sticker *sticker;

	assert(song != NULL);
	assert(song_in_database(song));

	uri = song_get_uri(song);
	sticker = sticker_load("song", uri);
	g_free(uri);

	return sticker;
}
bool
sticker_song_delete_value(const struct song *song, const char *name)
{
	char *uri;
	bool success;

	assert(song != NULL);
	assert(song_in_database(song));

	uri = song_get_uri(song);
	success = sticker_delete_value("song", uri, name);
	g_free(uri);

	return success;
}
bool
sticker_song_delete(const struct song *song)
{
	char *uri;
	bool ret;

	assert(song != NULL);
	assert(song_in_database(song));

	uri = song_get_uri(song);
	ret = sticker_delete("song", uri);
	g_free(uri);

	return ret;
}
bool
sticker_song_set_value(const struct song *song,
		       const char *name, const char *value)
{
	char *uri;
	bool ret;

	assert(song != NULL);
	assert(song_in_database(song));

	uri = song_get_uri(song);
	ret = sticker_store_value("song", uri, name, value);
	g_free(uri);

	return ret;
}
示例#9
0
static bool
locate_tag_search(const struct song *song, enum tag_type type, const char *str)
{
	bool ret = false;

	if (type == LOCATE_TAG_FILE_TYPE || (int)type == LOCATE_TAG_ANY_TYPE) {
		char *uri = song_get_uri(song);
		char *p = g_utf8_casefold(uri, -1);
		g_free(uri);

		if (strstr(p, str))
			ret = true;
		g_free(p);
		if (ret == 1 || type == LOCATE_TAG_FILE_TYPE)
			return ret;
	}

	if (!song->tag)
		return false;

	bool visited_types[TAG_NUM_OF_ITEM_TYPES];
	memset(visited_types, 0, sizeof(visited_types));

	for (unsigned i = 0; i < song->tag->num_items && !ret; i++) {
		visited_types[song->tag->items[i]->type] = true;
		if ((int)type != LOCATE_TAG_ANY_TYPE &&
		    song->tag->items[i]->type != type) {
			continue;
		}

		char *duplicate = g_utf8_casefold(song->tag->items[i]->value, -1);
		if (*str && strstr(duplicate, str))
			ret = true;
		g_free(duplicate);
	}

	/** If the search critieron was not visited during the sweep
	 * through the song's tag, it means this field is absent from
	 * the tag or empty. Thus, if the searched string is also
	 *  empty (first char is a \0), then it's a match as well and
	 *  we should return true.
	 */
	if (!*str && !visited_types[type])
		return true;

	return ret;
}
示例#10
0
/**
 * Queue a song, addressed by its order number.
 */
static void
playlist_queue_song_order(struct playlist *playlist, unsigned order)
{
	struct song *song;
	char *uri;

	assert(queue_valid_order(&playlist->queue, order));

	playlist->queued = order;

	song = queue_get_order(&playlist->queue, order);
	uri = song_get_uri(song);
	g_debug("queue song %i:\"%s\"", playlist->queued, uri);
	g_free(uri);

	pc_enqueue_song(song);
}
示例#11
0
void
playlist_play_order(struct playlist *playlist, int orderNum)
{
	struct song *song;
	char *uri;

	playlist->playing = true;
	playlist->queued = -1;

	song = queue_get_order(&playlist->queue, orderNum);

	uri = song_get_uri(song);
	g_debug("play %i:\"%s\"", orderNum, uri);
	g_free(uri);

	pc_play(song);
	playlist->current = orderNum;
}
/**
 * This is called at the border between two songs: the audio output
 * has consumed all chunks of the current song, and we should start
 * sending chunks from the next one.
 *
 * The player lock is not held.
 *
 * @return true on success, false on error (playback will be stopped)
 */
static bool
player_song_border(struct player *player)
{
	player->xfade = XFADE_UNKNOWN;

	char *uri = song_get_uri(player->song);
	g_message("played \"%s\"", uri);
	g_free(uri);

	music_pipe_free(player->pipe);
	player->pipe = player->dc->pipe;

	audio_output_all_song_border();

	if (!player_wait_for_decoder(player))
		return false;

	return true;
}
示例#13
0
文件: playlist.c 项目: pallotron/MPD
void
playlist_play_order(struct playlist *playlist, struct player_control *pc,
		    int orderNum)
{
	char *uri;

	playlist->playing = true;
	playlist->queued = -1;

	struct song *song =
		song_dup_detached(queue_get_order(&playlist->queue, orderNum));

	uri = song_get_uri(song);
	g_debug("play %i:\"%s\"", orderNum, uri);
	g_free(uri);

	pc_play(pc, song);
	playlist->current = orderNum;
}
void
playlist_print_song(FILE *file, const struct song *song)
{
	if (playlist_saveAbsolutePaths && song_in_database(song)) {
		char *path = map_song_fs(song);
		if (path != NULL) {
			fprintf(file, "%s\n", path);
			g_free(path);
		}
	} else {
		char *uri = song_get_uri(song), *uri_fs;

		uri_fs = utf8_to_fs_charset(uri);
		g_free(uri);

		fprintf(file, "%s\n", uri_fs);
		g_free(uri_fs);
	}
}
示例#15
0
static bool
locate_tag_match(const struct song *song, enum tag_type type, const char *str)
{
	if (type == LOCATE_TAG_FILE_TYPE || (int)type == LOCATE_TAG_ANY_TYPE) {
		char *uri = song_get_uri(song);
		bool matches = strcmp(str, uri) == 0;
		g_free(uri);

		if (matches)
			return true;

		if (type == LOCATE_TAG_FILE_TYPE)
			return false;
	}

	if (!song->tag)
		return false;

	bool visited_types[TAG_NUM_OF_ITEM_TYPES];
	memset(visited_types, 0, sizeof(visited_types));

	for (unsigned i = 0; i < song->tag->num_items; i++) {
		visited_types[song->tag->items[i]->type] = true;
		if ((int)type != LOCATE_TAG_ANY_TYPE &&
		    song->tag->items[i]->type != type) {
			continue;
		}

		if (0 == strcmp(str, song->tag->items[i]->value))
			return true;
	}

	/** If the search critieron was not visited during the sweep
	 * through the song's tag, it means this field is absent from
	 * the tag or empty. Thus, if the searched string is also
	 *  empty (first char is a \0), then it's a match as well and
	 *  we should return true.
	 */
	if (!*str && !visited_types[type])
		return true;

	return false;
}
示例#16
0
文件: playlist.c 项目: pallotron/MPD
/**
 * Queue a song, addressed by its order number.
 */
static void
playlist_queue_song_order(struct playlist *playlist, struct player_control *pc,
			  unsigned order)
{
	char *uri;

	assert(queue_valid_order(&playlist->queue, order));

	playlist->queued = order;

	struct song *song =
		song_dup_detached(queue_get_order(&playlist->queue, order));

	uri = song_get_uri(song);
	g_debug("queue song %i:\"%s\"", playlist->queued, uri);
	g_free(uri);

	pc_enqueue_song(pc, song);
}
示例#17
0
static void
decoder_run(struct decoder_control *dc)
{
	const struct song *song = dc->song;
	char *uri;

	assert(song != NULL);

	if (song_is_file(song))
		uri = map_song_fs(song);
	else
		uri = song_get_uri(song);

	if (uri == NULL) {
		dc->state = DECODE_STATE_ERROR;
		decoder_command_finished_locked(dc);
		return;
	}

	decoder_run_song(dc, song, uri);
	g_free(uri);

}
示例#18
0
static void
decoder_run_song(struct decoder_control *dc,
		 const struct song *song, const char *uri)
{
	struct decoder decoder = {
		.dc = dc,
		.initial_seek_pending = dc->start_ms > 0,
		.initial_seek_running = false,
	};
	int ret;

	decoder.timestamp = 0.0;
	decoder.seeking = false;
	decoder.song_tag = song->tag != NULL && song_is_file(song)
		? tag_dup(song->tag) : NULL;
	decoder.stream_tag = NULL;
	decoder.decoder_tag = NULL;
	decoder.chunk = NULL;

	dc->state = DECODE_STATE_START;

	decoder_command_finished_locked(dc);

	pcm_convert_init(&decoder.conv_state);

	ret = song_is_file(song)
		? decoder_run_file(&decoder, uri)
		: decoder_run_stream(&decoder, uri);

	decoder_unlock(dc);

	pcm_convert_deinit(&decoder.conv_state);

	/* flush the last chunk */

	if (decoder.chunk != NULL)
		decoder_flush_chunk(&decoder);

	if (decoder.song_tag != NULL)
		tag_free(decoder.song_tag);

	if (decoder.stream_tag != NULL)
		tag_free(decoder.stream_tag);

	if (decoder.decoder_tag != NULL)
		tag_free(decoder.decoder_tag);

	decoder_lock(dc);

	dc->state = ret ? DECODE_STATE_STOP : DECODE_STATE_ERROR;
}

static void
decoder_run(struct decoder_control *dc)
{
	const struct song *song = dc->song;
	char *uri;

	assert(song != NULL);

	if (song_is_file(song))
		uri = map_song_fs(song);
	else
		uri = song_get_uri(song);

	if (uri == NULL) {
		dc->state = DECODE_STATE_ERROR;
		decoder_command_finished_locked(dc);
		return;
	}

	decoder_run_song(dc, song, uri);
	g_free(uri);

}

static gpointer
decoder_task(gpointer arg)
{
	struct decoder_control *dc = arg;

	decoder_lock(dc);

	do {
		assert(dc->state == DECODE_STATE_STOP ||
		       dc->state == DECODE_STATE_ERROR);

		switch (dc->command) {
		case DECODE_COMMAND_START:
			dc_mixramp_start(dc, NULL);
			dc_mixramp_prev_end(dc, dc->mixramp_end);
			dc->mixramp_end = NULL; /* Don't free, it's copied above. */
			dc->replay_gain_prev_db = dc->replay_gain_db;
			dc->replay_gain_db = 0;

                        /* fall through */

		case DECODE_COMMAND_SEEK:
			decoder_run(dc);
			break;

		case DECODE_COMMAND_STOP:
			decoder_command_finished_locked(dc);
			break;

		case DECODE_COMMAND_NONE:
			decoder_wait(dc);
			break;
		}
	} while (dc->command != DECODE_COMMAND_NONE || !dc->quit);

	decoder_unlock(dc);

	return NULL;
}

void
decoder_thread_start(struct decoder_control *dc)
{
	GError *e = NULL;

	assert(dc->thread == NULL);

	dc->quit = false;

	dc->thread = g_thread_create(decoder_task, dc, true, &e);
	if (dc->thread == NULL)
		MPD_ERROR("Failed to spawn decoder task: %s", e->message);
}
示例#19
0
static void
decoder_run_song(struct decoder_control *dc,
		 const struct song *song, const char *uri)
{
	struct decoder decoder = {
		.dc = dc,
		.initial_seek_pending = dc->start_ms > 0,
		.initial_seek_running = false,
	};
	int ret;

	decoder.timestamp = 0.0;
	decoder.seeking = false;
	decoder.song_tag = song->tag != NULL && song_is_file(song)
		? tag_dup(song->tag) : NULL;
	decoder.stream_tag = NULL;
	decoder.decoder_tag = NULL;
	decoder.chunk = NULL;

	dc->state = DECODE_STATE_START;

	decoder_command_finished_locked(dc);

	pcm_convert_init(&decoder.conv_state);

	ret = song_is_file(song)
		? decoder_run_file(&decoder, uri)
		: decoder_run_stream(&decoder, uri);

	decoder_unlock(dc);

	pcm_convert_deinit(&decoder.conv_state);

	/* flush the last chunk */

	if (decoder.chunk != NULL)
		decoder_flush_chunk(&decoder);

	if (decoder.song_tag != NULL)
		tag_free(decoder.song_tag);

	if (decoder.stream_tag != NULL)
		tag_free(decoder.stream_tag);

	if (decoder.decoder_tag != NULL)
		tag_free(decoder.decoder_tag);

	decoder_lock(dc);

	if (ret)
		dc->state = DECODE_STATE_STOP;
	else {
		dc->state = DECODE_STATE_ERROR;

		const char *error_uri = song->uri;
		char *allocated = uri_remove_auth(error_uri);
		if (allocated != NULL)
			error_uri = allocated;

		dc->error = g_error_new(decoder_quark(), 0,
					"Failed to decode %s", error_uri);
		g_free(allocated);
	}
}

static void
decoder_run(struct decoder_control *dc)
{
	dc_clear_error(dc);

	const struct song *song = dc->song;
	char *uri;

	assert(song != NULL);

	if (song_is_file(song))
		uri = map_song_fs(song);
	else
		uri = song_get_uri(song);

	if (uri == NULL) {
		dc->state = DECODE_STATE_ERROR;
		dc->error = g_error_new(decoder_quark(), 0,
					"Failed to map song");

		decoder_command_finished_locked(dc);
		return;
	}

	decoder_run_song(dc, song, uri);
	g_free(uri);

}
示例#20
0
static char *
pc_errored_song_uri(void)
{
	return song_get_uri(pc.errored_song);
}
示例#21
0
文件: decoder_api.c 项目: azuwis/mpd
char *decoder_get_uri(G_GNUC_UNUSED struct decoder *decoder)
{
	return song_get_uri(dc.current_song);
}
/**
 * The decoder has acknowledged the "START" command (see
 * player_wait_for_decoder()).  This function checks if the decoder
 * initialization has completed yet.
 *
 * The player lock is not held.
 */
static bool
player_check_decoder_startup(struct player *player)
{
	struct player_control *pc = player->pc;
	struct decoder_control *dc = player->dc;

	assert(player->decoder_starting);

	decoder_lock(dc);

	if (decoder_has_failed(dc)) {
		/* the decoder failed */
		decoder_unlock(dc);

		player_lock(pc);
		pc->errored_song = dc->song;
		pc->error = PLAYER_ERROR_FILE;
		player_unlock(pc);

		return false;
	} else if (!decoder_is_starting(dc)) {
		/* the decoder is ready and ok */

		decoder_unlock(dc);

		if (audio_format_defined(&player->play_audio_format) &&
		    !audio_output_all_wait(pc, 1))
			/* the output devices havn't finished playing
			   all chunks yet - wait for that */
			return true;

		player_lock(pc);
		pc->total_time = real_song_duration(dc->song, dc->total_time);
		pc->audio_format = dc->in_audio_format;
		player_unlock(pc);

		player->play_audio_format = dc->out_audio_format;
		player->decoder_starting = false;

		if (!player->paused &&
		    !audio_output_all_open(&dc->out_audio_format,
					   player_buffer)) {
			char *uri = song_get_uri(dc->song);
			g_warning("problems opening audio device "
				  "while playing \"%s\"", uri);
			g_free(uri);

			player_lock(pc);
			pc->error = PLAYER_ERROR_AUDIO;

			/* pause: the user may resume playback as soon
			   as an audio output becomes available */
			pc->state = PLAYER_STATE_PAUSE;
			player_unlock(pc);

			player->paused = true;
			return true;
		}

		return true;
	} else {
		/* the decoder is not yet ready; wait
		   some more */
		player_wait_decoder(pc, dc);
		decoder_unlock(dc);

		return true;
	}
}