Ejemplo n.º 1
0
float
decoder_replay_gain(struct decoder *decoder,
		    const struct replay_gain_info *replay_gain_info)
{
	float return_db = 0;
	assert(decoder != NULL);

	if (replay_gain_info != NULL) {
		static unsigned serial;
		if (++serial == 0)
			serial = 1;

		if (REPLAY_GAIN_OFF != replay_gain_mode) {
			return_db = 20.0 * log10f(
				replay_gain_tuple_scale(
					&replay_gain_info->tuples[replay_gain_get_real_mode()],
					replay_gain_preamp, replay_gain_missing_preamp,
					replay_gain_limit));
		}

		decoder->replay_gain_info = *replay_gain_info;
		decoder->replay_gain_serial = serial;

		if (decoder->chunk != NULL) {
			/* flush the current chunk because the new
			   replay gain values affect the following
			   samples */
			decoder_flush_chunk(decoder);
			player_lock_signal();
		}
	} else
		decoder->replay_gain_serial = 0;

	return return_db;
}
Ejemplo n.º 2
0
static void
decoder_run_song(struct decoder_control *dc,
		 const struct song *song, const char *uri)
{
	struct decoder decoder = {
		.dc = dc,
	};
	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;
}
Ejemplo n.º 3
0
/**
 * Sends a #tag as-is to the music pipe.  Flushes the current chunk
 * (decoder.chunk) if there is one.
 */
static enum decoder_command
do_send_tag(struct decoder *decoder, struct input_stream *is,
	    const struct tag *tag)
{
	struct music_chunk *chunk;

	if (decoder->chunk != NULL) {
		/* there is a partial chunk - flush it, we want the
		   tag in a new chunk */
		decoder_flush_chunk(decoder);
		player_lock_signal();
	}

	assert(decoder->chunk == NULL);

	chunk = decoder_get_chunk(decoder, is);
	if (chunk == NULL) {
		assert(decoder->dc->command != DECODE_COMMAND_NONE);
		return decoder->dc->command;
	}

	chunk->tag = tag_dup(tag);
	return DECODE_COMMAND_NONE;
}
Ejemplo n.º 4
0
void
decoder_replay_gain(struct decoder *decoder,
		    const struct replay_gain_info *replay_gain_info)
{
	assert(decoder != NULL);

	if (replay_gain_info != NULL) {
		static unsigned serial;
		if (++serial == 0)
			serial = 1;

		decoder->replay_gain_info = *replay_gain_info;
		decoder->replay_gain_serial = serial;

		if (decoder->chunk != NULL) {
			/* flush the current chunk because the new
			   replay gain values affect the following
			   samples */
			decoder_flush_chunk(decoder);
			player_lock_signal();
		}
	} else
		decoder->replay_gain_serial = 0;
}
Ejemplo n.º 5
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);
}
Ejemplo n.º 6
0
enum decoder_command
decoder_data(struct decoder *decoder,
	     struct input_stream *is,
	     const void *_data, size_t length,
	     uint16_t kbit_rate)
{
	struct decoder_control *dc = decoder->dc;
	const char *data = _data;
	GError *error = NULL;
	enum decoder_command cmd;

	assert(dc->state == DECODE_STATE_DECODE);
	assert(dc->pipe != NULL);
	assert(length % audio_format_frame_size(&dc->in_audio_format) == 0);

	decoder_lock(dc);
	cmd = decoder_get_virtual_command(decoder);
	decoder_unlock(dc);

	if (cmd == DECODE_COMMAND_STOP || cmd == DECODE_COMMAND_SEEK ||
	    length == 0)
		return cmd;

	/* send stream tags */

	if (update_stream_tag(decoder, is)) {
		if (decoder->decoder_tag != NULL) {
			/* merge with tag from decoder plugin */
			struct tag *tag;

			tag = tag_merge(decoder->decoder_tag,
					decoder->stream_tag);
			cmd = do_send_tag(decoder, is, tag);
			tag_free(tag);
		} else
			/* send only the stream tag */
			cmd = do_send_tag(decoder, is, decoder->stream_tag);

		if (cmd != DECODE_COMMAND_NONE)
			return cmd;
	}

	if (!audio_format_equals(&dc->in_audio_format, &dc->out_audio_format)) {
		data = pcm_convert(&decoder->conv_state,
				   &dc->in_audio_format, data, length,
				   &dc->out_audio_format, &length,
				   &error);
		if (data == NULL) {
			/* the PCM conversion has failed - stop
			   playback, since we have no better way to
			   bail out */
			g_warning("%s", error->message);
			return DECODE_COMMAND_STOP;
		}
	}

	while (length > 0) {
		struct music_chunk *chunk;
		char *dest;
		size_t nbytes;
		bool full;

		chunk = decoder_get_chunk(decoder, is);
		if (chunk == NULL) {
			assert(dc->command != DECODE_COMMAND_NONE);
			return dc->command;
		}

		dest = music_chunk_write(chunk, &dc->out_audio_format,
					 decoder->timestamp -
					 dc->song->start_ms / 1000.0,
					 kbit_rate, &nbytes);
		if (dest == NULL) {
			/* the chunk is full, flush it */
			decoder_flush_chunk(decoder);
			player_lock_signal();
			continue;
		}

		assert(nbytes > 0);

		if (nbytes > length)
			nbytes = length;

		/* copy the buffer */

		memcpy(dest, data, nbytes);

		/* expand the music pipe chunk */

		full = music_chunk_expand(chunk, &dc->out_audio_format, nbytes);
		if (full) {
			/* the chunk is full, flush it */
			decoder_flush_chunk(decoder);
			player_lock_signal();
		}

		data += nbytes;
		length -= nbytes;

		decoder->timestamp += (double)nbytes /
			audio_format_time_to_size(&dc->out_audio_format);

		if (dc->end_ms > 0 &&
		    decoder->timestamp >= dc->end_ms / 1000.0)
			/* the end of this range has been reached:
			   stop decoding */
			return DECODE_COMMAND_STOP;
	}

	return DECODE_COMMAND_NONE;
}
Ejemplo n.º 7
0
enum decoder_command
decoder_data(struct decoder *decoder,
	     struct input_stream *is,
	     const void *_data, size_t length,
	     float data_time, uint16_t bitRate,
	     struct replay_gain_info *replay_gain_info)
{
	const char *data = _data;

	assert(dc.state == DECODE_STATE_DECODE);
	assert(length % audio_format_frame_size(&dc.in_audio_format) == 0);

	if (dc.command == DECODE_COMMAND_STOP ||
	    dc.command == DECODE_COMMAND_SEEK ||
	    length == 0)
		return dc.command;

	/* send stream tags */

	if (update_stream_tag(decoder, is)) {
		enum decoder_command cmd;

		if (decoder->decoder_tag != NULL) {
			/* merge with tag from decoder plugin */
			struct tag *tag;

			tag = tag_merge(decoder->stream_tag,
					decoder->decoder_tag);
			cmd = do_send_tag(decoder, is, tag);
			tag_free(tag);
		} else
			/* send only the stream tag */
			cmd = do_send_tag(decoder, is, decoder->stream_tag);

		if (cmd != DECODE_COMMAND_NONE)
			return cmd;
	}

	if (!audio_format_equals(&dc.in_audio_format, &dc.out_audio_format)) {
		data = pcm_convert(&decoder->conv_state,
				   &dc.in_audio_format, data, length,
				   &dc.out_audio_format, &length);

		/* under certain circumstances, pcm_convert() may
		   return an empty buffer - this condition should be
		   investigated further, but for now, do this check as
		   a workaround: */
		if (data == NULL)
			return DECODE_COMMAND_NONE;
	}

	while (length > 0) {
		struct music_chunk *chunk;
		char *dest;
		size_t nbytes;
		bool full;

		chunk = decoder_get_chunk(decoder, is);
		if (chunk == NULL) {
			assert(dc.command != DECODE_COMMAND_NONE);
			return dc.command;
		}

		dest = music_chunk_write(chunk, &dc.out_audio_format,
					 data_time, bitRate, &nbytes);
		if (dest == NULL) {
			/* the chunk is full, flush it */
			decoder_flush_chunk(decoder);
			notify_signal(&pc.notify);
			continue;
		}

		assert(nbytes > 0);

		if (nbytes > length)
			nbytes = length;

		/* copy the buffer */

		memcpy(dest, data, nbytes);

		/* apply replay gain or normalization */

		if (replay_gain_info != NULL &&
		    replay_gain_mode != REPLAY_GAIN_OFF)
			replay_gain_apply(replay_gain_info, dest, nbytes,
					  &dc.out_audio_format);
		else if (normalizationEnabled)
			normalizeData(dest, nbytes, &dc.out_audio_format);

		/* expand the music pipe chunk */

		full = music_chunk_expand(chunk, &dc.out_audio_format, nbytes);
		if (full) {
			/* the chunk is full, flush it */
			decoder_flush_chunk(decoder);
			notify_signal(&pc.notify);
		}

		data += nbytes;
		length -= nbytes;
	}

	return DECODE_COMMAND_NONE;
}
Ejemplo n.º 8
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);

}