Example #1
0
static struct song *
apply_song_metadata(struct song *dest, const struct song *src)
{
	struct song *tmp;

	assert(dest != NULL);
	assert(src != NULL);

	if (src->tag == NULL && src->start_ms == 0 && src->end_ms == 0)
		return dest;

	if (song_in_database(dest)) {
		char *path_fs = map_song_fs(dest);
		if (path_fs == NULL)
			return dest;

		tmp = song_file_new(path_fs, NULL);
		g_free(path_fs);

		merge_song_metadata(tmp, dest, src);
	} else {
		tmp = song_file_new(dest->uri, NULL);
		merge_song_metadata(tmp, dest, src);
		song_free(dest);
	}

	return tmp;
}
Example #2
0
File: song.c Project: azuwis/mpd
bool
song_file_update(struct song *song)
{
	const char *suffix;
	char *path_fs;
	const struct decoder_plugin *plugin;
	struct stat st;

	assert(song_is_file(song));

	/* check if there's a suffix and a plugin */

	suffix = uri_get_suffix(song->url);
	if (suffix == NULL)
		return false;

	plugin = decoder_plugin_from_suffix(suffix, false);
	if (plugin == NULL)
		return false;

	path_fs = map_song_fs(song);
	if (path_fs == NULL)
		return false;

	if (song->tag != NULL) {
		tag_free(song->tag);
		song->tag = NULL;
	}

	if (stat(path_fs, &st) < 0 || !S_ISREG(st.st_mode)) {
		g_free(path_fs);
		return false;
	}

	song->mtime = st.st_mtime;

	do {
		song->tag = plugin->tag_dup(path_fs);
		if (song->tag != NULL)
			break;

		plugin = decoder_plugin_from_suffix(suffix, true);
	} while (plugin != NULL);

	if (song->tag != NULL && tag_is_empty(song->tag))
		song->tag = tag_fallback(path_fs, song->tag);

	g_free(path_fs);
	return song->tag != NULL;
}
/* passed to songvec_for_each */
static int
delete_song_if_removed(struct song *song, void *_data)
{
	struct directory *dir = _data;
	char *path;
	struct stat st;

	if ((path = map_song_fs(song)) == NULL ||
	    stat(path, &st) < 0 || !S_ISREG(st.st_mode)) {
		delete_song(dir, song);
		modified = true;
	}

	g_free(path);
	return 0;
}
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);
	}
}
Example #5
0
static struct song *
apply_song_metadata(struct song *dest, const struct song *src)
{
	struct song *tmp;

	assert(dest != NULL);
	assert(src != NULL);

	if (src->tag == NULL && src->start_ms == 0 && src->end_ms == 0)
		return dest;

	if (song_in_database(dest)) {
		char *path_fs = map_song_fs(dest);
		if (path_fs == NULL)
			return dest;

		char *path_utf8 = fs_charset_to_utf8(path_fs);
		if (path_utf8 != NULL)
			g_free(path_fs);
		else
			path_utf8 = path_fs;

		tmp = song_file_new(path_utf8, NULL);
		g_free(path_utf8);

		merge_song_metadata(tmp, dest, src);
	} else {
		tmp = song_file_new(dest->uri, NULL);
		merge_song_metadata(tmp, dest, src);
	}

	if (dest->tag != NULL && dest->tag->time > 0 &&
	    src->start_ms > 0 && src->end_ms == 0 &&
	    src->start_ms / 1000 < (unsigned)dest->tag->time)
		/* the range is open-ended, and the playlist plugin
		   did not know the total length of the song file
		   (e.g. last track on a CUE file); fix it up here */
		tmp->tag->time = dest->tag->time - src->start_ms / 1000;

	song_free(dest);
	return tmp;
}
Example #6
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);

}
Example #7
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);
}
Example #8
0
bool
song_file_update(struct song *song)
{
	const char *suffix;
	char *path_fs;
	const struct decoder_plugin *plugin;
	struct stat st;
	struct input_stream *is = NULL;

	assert(song_is_file(song));

	/* check if there's a suffix and a plugin */

	suffix = uri_get_suffix(song->uri);
	if (suffix == NULL)
		return false;

	plugin = decoder_plugin_from_suffix(suffix, NULL);
	if (plugin == NULL)
		return false;

	path_fs = map_song_fs(song);
	if (path_fs == NULL)
		return false;

	if (song->tag != NULL) {
		tag_free(song->tag);
		song->tag = NULL;
	}

	if (stat(path_fs, &st) < 0 || !S_ISREG(st.st_mode)) {
		g_free(path_fs);
		return false;
	}

	song->mtime = st.st_mtime;

	do {
		/* load file tag */
		song->tag = decoder_plugin_tag_dup(plugin, path_fs);
		if (song->tag != NULL)
			break;

		/* fall back to stream tag */
		if (plugin->stream_tag != NULL) {
			/* open the input_stream (if not already
			   open) */
			if (is == NULL)
				is = input_stream_open(path_fs, NULL);

			/* now try the stream_tag() method */
			if (is != NULL) {
				song->tag = decoder_plugin_stream_tag(plugin,
								      is);
				if (song->tag != NULL)
					break;

				input_stream_seek(is, 0, SEEK_SET, NULL);
			}
		}

		plugin = decoder_plugin_from_suffix(suffix, plugin);
	} while (plugin != NULL);

	if (is != NULL)
		input_stream_close(is);

	if (song->tag != NULL && tag_is_empty(song->tag))
		song->tag = tag_fallback(path_fs, song->tag);

	g_free(path_fs);
	return song->tag != NULL;
}
Example #9
0
bool
song_file_update(struct song *song)
{
    const char *suffix;
    char *path_fs;
    const struct decoder_plugin *plugin;
    struct stat st;
    struct input_stream *is = NULL;

    assert(song_is_file(song));

    /* check if there's a suffix and a plugin */

    suffix = uri_get_suffix(song->uri);
    if (suffix == NULL)
        return false;

    plugin = decoder_plugin_from_suffix(suffix, NULL);
    if (plugin == NULL)
        return false;

    path_fs = map_song_fs(song);
    if (path_fs == NULL)
        return false;

    if (song->tag != NULL) {
        tag_free(song->tag);
        song->tag = NULL;
    }

    if (stat(path_fs, &st) < 0 || !S_ISREG(st.st_mode)) {
        g_free(path_fs);
        return false;
    }

    song->mtime = st.st_mtime;

    GMutex *mutex = NULL;
    GCond *cond;
#if !GCC_CHECK_VERSION(4, 2)
    /* work around "may be used uninitialized in this function"
       false positive */
    cond = NULL;
#endif

    do {
        /* load file tag */
        song->tag = tag_new();
        if (decoder_plugin_scan_file(plugin, path_fs,
                                     &full_tag_handler, song->tag))
            break;

        tag_free(song->tag);
        song->tag = NULL;

        /* fall back to stream tag */
        if (plugin->scan_stream != NULL) {
            /* open the input_stream (if not already
               open) */
            if (is == NULL) {
                mutex = g_mutex_new();
                cond = g_cond_new();
                is = input_stream_open(path_fs, mutex, cond,
                                       NULL);
            }

            /* now try the stream_tag() method */
            if (is != NULL) {
                song->tag = tag_new();
                if (decoder_plugin_scan_stream(plugin, is,
                                               &full_tag_handler,
                                               song->tag))
                    break;

                tag_free(song->tag);
                song->tag = NULL;

                input_stream_lock_seek(is, 0, SEEK_SET, NULL);
            }
        }

        plugin = decoder_plugin_from_suffix(suffix, plugin);
    } while (plugin != NULL);

    if (is != NULL)
        input_stream_close(is);

    if (mutex != NULL) {
        g_cond_free(cond);
        g_mutex_free(mutex);
    }

    if (song->tag != NULL && tag_is_empty(song->tag))
        tag_scan_fallback(path_fs, &full_tag_handler, song->tag);

    g_free(path_fs);
    return song->tag != NULL;
}
Example #10
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);

}