decoder/Client: new interface which wraps struct Decoder
Prepare for a Decoder API redesign based on an abstract class with virtual methods.
This commit is contained in:
		
							
								
								
									
										31
									
								
								src/decoder/Client.hxx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/decoder/Client.hxx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| /* | ||||
|  * Copyright 2003-2016 The Music Player Daemon Project | ||||
|  * 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_DECODER_CLIENT_HXX | ||||
| #define MPD_DECODER_CLIENT_HXX | ||||
|  | ||||
| #include "check.h" | ||||
|  | ||||
| /** | ||||
|  * An interface between the decoder plugin and the MPD core. | ||||
|  */ | ||||
| class DecoderClient { | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| @@ -38,10 +38,11 @@ | ||||
| #include <math.h> | ||||
|  | ||||
| void | ||||
| decoder_initialized(Decoder &decoder, | ||||
| decoder_initialized(DecoderClient &client, | ||||
| 		    const AudioFormat audio_format, | ||||
| 		    bool seekable, SignedSongTime duration) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
| 	DecoderControl &dc = decoder.dc; | ||||
| 	struct audio_format_string af_string; | ||||
|  | ||||
| @@ -91,8 +92,9 @@ decoder_initialized(Decoder &decoder, | ||||
|  */ | ||||
| gcc_pure | ||||
| static bool | ||||
| decoder_prepare_initial_seek(Decoder &decoder) | ||||
| decoder_prepare_initial_seek(DecoderClient &client) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
| 	const DecoderControl &dc = decoder.dc; | ||||
| 	assert(dc.pipe != nullptr); | ||||
|  | ||||
| @@ -138,8 +140,10 @@ decoder_prepare_initial_seek(Decoder &decoder) | ||||
|  */ | ||||
| gcc_pure | ||||
| static DecoderCommand | ||||
| decoder_get_virtual_command(Decoder &decoder) | ||||
| decoder_get_virtual_command(DecoderClient &client) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
|  | ||||
| 	if (decoder.error) | ||||
| 		/* an error has occurred: stop the decoder plugin */ | ||||
| 		return DecoderCommand::STOP; | ||||
| @@ -155,21 +159,24 @@ decoder_get_virtual_command(Decoder &decoder) | ||||
|  | ||||
| gcc_pure | ||||
| static DecoderCommand | ||||
| decoder_lock_get_virtual_command(Decoder &decoder) | ||||
| decoder_lock_get_virtual_command(DecoderClient &client) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
| 	const ScopeLock protect(decoder.dc.mutex); | ||||
| 	return decoder_get_virtual_command(decoder); | ||||
| } | ||||
|  | ||||
| DecoderCommand | ||||
| decoder_get_command(Decoder &decoder) | ||||
| decoder_get_command(DecoderClient &client) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
| 	return decoder_lock_get_virtual_command(decoder); | ||||
| } | ||||
|  | ||||
| void | ||||
| decoder_command_finished(Decoder &decoder) | ||||
| decoder_command_finished(DecoderClient &client) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
| 	DecoderControl &dc = decoder.dc; | ||||
|  | ||||
| 	const ScopeLock protect(dc.mutex); | ||||
| @@ -211,8 +218,9 @@ decoder_command_finished(Decoder &decoder) | ||||
| } | ||||
|  | ||||
| SongTime | ||||
| decoder_seek_time(Decoder &decoder) | ||||
| decoder_seek_time(DecoderClient &client) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
| 	const DecoderControl &dc = decoder.dc; | ||||
|  | ||||
| 	assert(dc.pipe != nullptr); | ||||
| @@ -228,15 +236,18 @@ decoder_seek_time(Decoder &decoder) | ||||
| } | ||||
|  | ||||
| uint64_t | ||||
| decoder_seek_where_frame(Decoder &decoder) | ||||
| decoder_seek_where_frame(DecoderClient &client) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
| 	const DecoderControl &dc = decoder.dc; | ||||
|  | ||||
| 	return decoder_seek_time(decoder).ToScale<uint64_t>(dc.in_audio_format.sample_rate); | ||||
| } | ||||
|  | ||||
| void decoder_seek_error(Decoder & decoder) | ||||
| void | ||||
| decoder_seek_error(DecoderClient &client) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
| 	DecoderControl &dc = decoder.dc; | ||||
|  | ||||
| 	assert(dc.pipe != nullptr); | ||||
| @@ -257,8 +268,10 @@ void decoder_seek_error(Decoder & decoder) | ||||
| } | ||||
|  | ||||
| InputStreamPtr | ||||
| decoder_open_uri(Decoder &decoder, const char *uri) | ||||
| decoder_open_uri(DecoderClient &client, const char *uri) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
|  | ||||
| 	assert(decoder.dc.state == DecoderState::START || | ||||
| 	       decoder.dc.state == DecoderState::DECODE); | ||||
|  | ||||
| @@ -311,11 +324,12 @@ decoder_check_cancel_read(const Decoder *decoder) | ||||
| } | ||||
|  | ||||
| size_t | ||||
| decoder_read(Decoder *decoder, | ||||
| decoder_read(DecoderClient *client, | ||||
| 	     InputStream &is, | ||||
| 	     void *buffer, size_t length) | ||||
| try { | ||||
| 	/* XXX don't allow decoder==nullptr */ | ||||
| 	auto *decoder = (Decoder *)client; | ||||
|  | ||||
| 	assert(decoder == nullptr || | ||||
| 	       decoder->dc.state == DecoderState::START || | ||||
| @@ -342,6 +356,7 @@ try { | ||||
|  | ||||
| 	return nbytes; | ||||
| } catch (const std::runtime_error &e) { | ||||
| 	auto *decoder = (Decoder *)client; | ||||
| 	if (decoder != nullptr) | ||||
| 		decoder->error = std::current_exception(); | ||||
| 	else | ||||
| @@ -350,13 +365,13 @@ try { | ||||
| } | ||||
|  | ||||
| bool | ||||
| decoder_read_full(Decoder *decoder, InputStream &is, | ||||
| decoder_read_full(DecoderClient *client, InputStream &is, | ||||
| 		  void *_buffer, size_t size) | ||||
| { | ||||
| 	uint8_t *buffer = (uint8_t *)_buffer; | ||||
|  | ||||
| 	while (size > 0) { | ||||
| 		size_t nbytes = decoder_read(decoder, is, buffer, size); | ||||
| 		size_t nbytes = decoder_read(client, is, buffer, size); | ||||
| 		if (nbytes == 0) | ||||
| 			return false; | ||||
|  | ||||
| @@ -368,11 +383,11 @@ decoder_read_full(Decoder *decoder, InputStream &is, | ||||
| } | ||||
|  | ||||
| bool | ||||
| decoder_skip(Decoder *decoder, InputStream &is, size_t size) | ||||
| decoder_skip(DecoderClient *client, InputStream &is, size_t size) | ||||
| { | ||||
| 	while (size > 0) { | ||||
| 		char buffer[1024]; | ||||
| 		size_t nbytes = decoder_read(decoder, is, buffer, | ||||
| 		size_t nbytes = decoder_read(client, is, buffer, | ||||
| 					     std::min(sizeof(buffer), size)); | ||||
| 		if (nbytes == 0) | ||||
| 			return false; | ||||
| @@ -384,10 +399,11 @@ decoder_skip(Decoder *decoder, InputStream &is, size_t size) | ||||
| } | ||||
|  | ||||
| void | ||||
| decoder_timestamp(Decoder &decoder, double t) | ||||
| decoder_timestamp(DecoderClient &client, double t) | ||||
| { | ||||
| 	assert(t >= 0); | ||||
|  | ||||
| 	auto &decoder = (Decoder &)client; | ||||
| 	decoder.timestamp = t; | ||||
| } | ||||
|  | ||||
| @@ -396,8 +412,9 @@ decoder_timestamp(Decoder &decoder, double t) | ||||
|  * (decoder.chunk) if there is one. | ||||
|  */ | ||||
| static DecoderCommand | ||||
| do_send_tag(Decoder &decoder, const Tag &tag) | ||||
| do_send_tag(DecoderClient &client, const Tag &tag) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
| 	MusicChunk *chunk; | ||||
|  | ||||
| 	if (decoder.current_chunk != nullptr) { | ||||
| @@ -419,8 +436,9 @@ do_send_tag(Decoder &decoder, const Tag &tag) | ||||
| } | ||||
|  | ||||
| static bool | ||||
| update_stream_tag(Decoder &decoder, InputStream *is) | ||||
| update_stream_tag(DecoderClient &client, InputStream *is) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
| 	Tag *tag; | ||||
|  | ||||
| 	tag = is != nullptr | ||||
| @@ -445,11 +463,12 @@ update_stream_tag(Decoder &decoder, InputStream *is) | ||||
| } | ||||
|  | ||||
| DecoderCommand | ||||
| decoder_data(Decoder &decoder, | ||||
| decoder_data(DecoderClient &client, | ||||
| 	     InputStream *is, | ||||
| 	     const void *data, size_t length, | ||||
| 	     uint16_t kbit_rate) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
| 	DecoderControl &dc = decoder.dc; | ||||
|  | ||||
| 	assert(dc.state == DecoderState::DECODE); | ||||
| @@ -552,9 +571,10 @@ decoder_data(Decoder &decoder, | ||||
| } | ||||
|  | ||||
| DecoderCommand | ||||
| decoder_tag(Decoder &decoder, InputStream *is, | ||||
| decoder_tag(DecoderClient &client, InputStream *is, | ||||
| 	    Tag &&tag) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
| 	gcc_unused const DecoderControl &dc = decoder.dc; | ||||
| 	DecoderCommand cmd; | ||||
|  | ||||
| @@ -596,9 +616,11 @@ decoder_tag(Decoder &decoder, InputStream *is, | ||||
| } | ||||
|  | ||||
| void | ||||
| decoder_replay_gain(Decoder &decoder, | ||||
| decoder_replay_gain(DecoderClient &client, | ||||
| 		    const ReplayGainInfo *replay_gain_info) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
|  | ||||
| 	if (replay_gain_info != nullptr) { | ||||
| 		static unsigned serial; | ||||
| 		if (++serial == 0) | ||||
| @@ -631,8 +653,9 @@ decoder_replay_gain(Decoder &decoder, | ||||
| } | ||||
|  | ||||
| void | ||||
| decoder_mixramp(Decoder &decoder, MixRampInfo &&mix_ramp) | ||||
| decoder_mixramp(DecoderClient &client, MixRampInfo &&mix_ramp) | ||||
| { | ||||
| 	auto &decoder = (Decoder &)client; | ||||
| 	DecoderControl &dc = decoder.dc; | ||||
|  | ||||
| 	dc.SetMixRamp(std::move(mix_ramp)); | ||||
|   | ||||
| @@ -44,6 +44,8 @@ | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| class DecoderClient; | ||||
|  | ||||
| /** | ||||
|  * Throw an instance of this class to stop decoding the current song | ||||
|  * (successfully).  It can be used to jump out of all of a decoder's | ||||
| @@ -63,7 +65,7 @@ class StopDecoder {}; | ||||
|  * unknown | ||||
|  */ | ||||
| void | ||||
| decoder_initialized(Decoder &decoder, | ||||
| decoder_initialized(DecoderClient &decoder, | ||||
| 		    AudioFormat audio_format, | ||||
| 		    bool seekable, SignedSongTime duration); | ||||
|  | ||||
| @@ -76,7 +78,7 @@ decoder_initialized(Decoder &decoder, | ||||
|  */ | ||||
| gcc_pure | ||||
| DecoderCommand | ||||
| decoder_get_command(Decoder &decoder); | ||||
| decoder_get_command(DecoderClient &decoder); | ||||
|  | ||||
| /** | ||||
|  * Called by the decoder when it has performed the requested command | ||||
| @@ -86,7 +88,7 @@ decoder_get_command(Decoder &decoder); | ||||
|  * @param decoder the decoder object | ||||
|  */ | ||||
| void | ||||
| decoder_command_finished(Decoder &decoder); | ||||
| decoder_command_finished(DecoderClient &decoder); | ||||
|  | ||||
| /** | ||||
|  * Call this when you have received the DecoderCommand::SEEK command. | ||||
| @@ -96,7 +98,7 @@ decoder_command_finished(Decoder &decoder); | ||||
|  */ | ||||
| gcc_pure | ||||
| SongTime | ||||
| decoder_seek_time(Decoder &decoder); | ||||
| decoder_seek_time(DecoderClient &decoder); | ||||
|  | ||||
| /** | ||||
|  * Call this when you have received the DecoderCommand::SEEK command. | ||||
| @@ -106,7 +108,7 @@ decoder_seek_time(Decoder &decoder); | ||||
|  */ | ||||
| gcc_pure | ||||
| uint64_t | ||||
| decoder_seek_where_frame(Decoder &decoder); | ||||
| decoder_seek_where_frame(DecoderClient &decoder); | ||||
|  | ||||
| /** | ||||
|  * Call this instead of decoder_command_finished() when seeking has | ||||
| @@ -115,7 +117,7 @@ decoder_seek_where_frame(Decoder &decoder); | ||||
|  * @param decoder the decoder object | ||||
|  */ | ||||
| void | ||||
| decoder_seek_error(Decoder &decoder); | ||||
| decoder_seek_error(DecoderClient &decoder); | ||||
|  | ||||
| /** | ||||
|  * Open a new #InputStream and wait until it's ready. | ||||
| @@ -125,7 +127,7 @@ decoder_seek_error(Decoder &decoder); | ||||
|  * Throws std::runtime_error on error. | ||||
|  */ | ||||
| InputStreamPtr | ||||
| decoder_open_uri(Decoder &decoder, const char *uri); | ||||
| decoder_open_uri(DecoderClient &decoder, const char *uri); | ||||
|  | ||||
| /** | ||||
|  * Blocking read from the input stream. | ||||
| @@ -138,11 +140,11 @@ decoder_open_uri(Decoder &decoder, const char *uri); | ||||
|  * occurs: end of file; error; command (like SEEK or STOP). | ||||
|  */ | ||||
| size_t | ||||
| decoder_read(Decoder *decoder, InputStream &is, | ||||
| decoder_read(DecoderClient *decoder, InputStream &is, | ||||
| 	     void *buffer, size_t length); | ||||
|  | ||||
| static inline size_t | ||||
| decoder_read(Decoder &decoder, InputStream &is, | ||||
| decoder_read(DecoderClient &decoder, InputStream &is, | ||||
| 	     void *buffer, size_t length) | ||||
| { | ||||
| 	return decoder_read(&decoder, is, buffer, length); | ||||
| @@ -156,7 +158,7 @@ decoder_read(Decoder &decoder, InputStream &is, | ||||
|  * data | ||||
|  */ | ||||
| bool | ||||
| decoder_read_full(Decoder *decoder, InputStream &is, | ||||
| decoder_read_full(DecoderClient *decoder, InputStream &is, | ||||
| 		  void *buffer, size_t size); | ||||
|  | ||||
| /** | ||||
| @@ -165,7 +167,7 @@ decoder_read_full(Decoder *decoder, InputStream &is, | ||||
|  * @return true on success, false on error or command | ||||
|  */ | ||||
| bool | ||||
| decoder_skip(Decoder *decoder, InputStream &is, size_t size); | ||||
| decoder_skip(DecoderClient *decoder, InputStream &is, size_t size); | ||||
|  | ||||
| /** | ||||
|  * Sets the time stamp for the next data chunk [seconds].  The MPD | ||||
| @@ -174,7 +176,7 @@ decoder_skip(Decoder *decoder, InputStream &is, size_t size); | ||||
|  * on the buffer size won't work. | ||||
|  */ | ||||
| void | ||||
| decoder_timestamp(Decoder &decoder, double t); | ||||
| decoder_timestamp(DecoderClient &decoder, double t); | ||||
|  | ||||
| /** | ||||
|  * This function is called by the decoder plugin when it has | ||||
| @@ -189,12 +191,12 @@ decoder_timestamp(Decoder &decoder, double t); | ||||
|  * command pending | ||||
|  */ | ||||
| DecoderCommand | ||||
| decoder_data(Decoder &decoder, InputStream *is, | ||||
| decoder_data(DecoderClient &decoder, InputStream *is, | ||||
| 	     const void *data, size_t length, | ||||
| 	     uint16_t kbit_rate); | ||||
|  | ||||
| static inline DecoderCommand | ||||
| decoder_data(Decoder &decoder, InputStream &is, | ||||
| decoder_data(DecoderClient &decoder, InputStream &is, | ||||
| 	     const void *data, size_t length, | ||||
| 	     uint16_t kbit_rate) | ||||
| { | ||||
| @@ -212,10 +214,10 @@ decoder_data(Decoder &decoder, InputStream &is, | ||||
|  * command pending | ||||
|  */ | ||||
| DecoderCommand | ||||
| decoder_tag(Decoder &decoder, InputStream *is, Tag &&tag); | ||||
| decoder_tag(DecoderClient &decoder, InputStream *is, Tag &&tag); | ||||
|  | ||||
| static inline DecoderCommand | ||||
| decoder_tag(Decoder &decoder, InputStream &is, Tag &&tag) | ||||
| decoder_tag(DecoderClient &decoder, InputStream &is, Tag &&tag) | ||||
| { | ||||
| 	return decoder_tag(decoder, &is, std::move(tag)); | ||||
| } | ||||
| @@ -227,13 +229,13 @@ decoder_tag(Decoder &decoder, InputStream &is, Tag &&tag) | ||||
|  * to invalidate the previous replay gain values | ||||
|  */ | ||||
| void | ||||
| decoder_replay_gain(Decoder &decoder, | ||||
| decoder_replay_gain(DecoderClient &decoder, | ||||
| 		    const ReplayGainInfo *replay_gain_info); | ||||
|  | ||||
| /** | ||||
|  * Store MixRamp tags. | ||||
|  */ | ||||
| void | ||||
| decoder_mixramp(Decoder &decoder, MixRampInfo &&mix_ramp); | ||||
| decoder_mixramp(DecoderClient &decoder, MixRampInfo &&mix_ramp); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -29,7 +29,7 @@ DecoderBuffer::Fill() | ||||
| 		/* buffer is full */ | ||||
| 		return false; | ||||
|  | ||||
| 	size_t nbytes = decoder_read(decoder, is, | ||||
| 	size_t nbytes = decoder_read(client, is, | ||||
| 				     w.data, w.size); | ||||
| 	if (nbytes == 0) | ||||
| 		/* end of file, I/O error or decoder command | ||||
| @@ -65,5 +65,5 @@ DecoderBuffer::Skip(size_t nbytes) | ||||
| 	buffer.Clear(); | ||||
| 	nbytes -= r.size; | ||||
|  | ||||
| 	return decoder_skip(decoder, is, nbytes); | ||||
| 	return decoder_skip(client, is, nbytes); | ||||
| } | ||||
|   | ||||
| @@ -27,7 +27,7 @@ | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
|  | ||||
| struct Decoder; | ||||
| class DecoderClient; | ||||
| class InputStream; | ||||
|  | ||||
| /** | ||||
| @@ -36,7 +36,7 @@ class InputStream; | ||||
|  * read it.  It will automatically handle shifting the buffer. | ||||
|  */ | ||||
| class DecoderBuffer { | ||||
| 	Decoder *const decoder; | ||||
| 	DecoderClient *const client; | ||||
| 	InputStream &is; | ||||
|  | ||||
| 	DynamicFifoBuffer<uint8_t> buffer; | ||||
| @@ -45,14 +45,14 @@ public: | ||||
| 	/** | ||||
| 	 * Creates a new buffer. | ||||
| 	 * | ||||
| 	 * @param _decoder the decoder object, used for decoder_read(), | ||||
| 	 * @param _client the decoder client, used for decoder_read(), | ||||
| 	 * may be nullptr | ||||
| 	 * @param _is the input stream object where we should read from | ||||
| 	 * @param _size the maximum size of the buffer | ||||
| 	 */ | ||||
| 	DecoderBuffer(Decoder *_decoder, InputStream &_is, | ||||
| 	DecoderBuffer(DecoderClient *_client, InputStream &_is, | ||||
| 		      size_t _size) | ||||
| 		:decoder(_decoder), is(_is), buffer(_size) {} | ||||
| 		:client(_client), is(_is), buffer(_size) {} | ||||
|  | ||||
| 	const InputStream &GetStream() const { | ||||
| 		return is; | ||||
|   | ||||
| @@ -20,6 +20,7 @@ | ||||
| #ifndef MPD_DECODER_INTERNAL_HXX | ||||
| #define MPD_DECODER_INTERNAL_HXX | ||||
|  | ||||
| #include "Client.hxx" | ||||
| #include "ReplayGainInfo.hxx" | ||||
|  | ||||
| #include <exception> | ||||
| @@ -29,7 +30,7 @@ struct MusicChunk; | ||||
| struct DecoderControl; | ||||
| struct Tag; | ||||
|  | ||||
| struct Decoder { | ||||
| struct Decoder final : DecoderClient { | ||||
| 	DecoderControl &dc; | ||||
|  | ||||
| 	/** | ||||
|   | ||||
| @@ -27,12 +27,7 @@ class InputStream; | ||||
| struct TagHandler; | ||||
| class Path; | ||||
| template<typename T> class AllocatedString; | ||||
|  | ||||
| /** | ||||
|  * Opaque handle which the decoder plugin passes to the functions in | ||||
|  * this header. | ||||
|  */ | ||||
| struct Decoder; | ||||
| class DecoderClient; | ||||
|  | ||||
| struct DecoderPlugin { | ||||
| 	const char *name; | ||||
| @@ -60,14 +55,14 @@ struct DecoderPlugin { | ||||
| 	 * possible, it is recommended to implement this method, | ||||
| 	 * because it is more versatile. | ||||
| 	 */ | ||||
| 	void (*stream_decode)(Decoder &decoder, InputStream &is); | ||||
| 	void (*stream_decode)(DecoderClient &client, InputStream &is); | ||||
|  | ||||
| 	/** | ||||
| 	 * Decode a local file. | ||||
| 	 * | ||||
| 	 * Either implement this method or stream_decode(). | ||||
| 	 */ | ||||
| 	void (*file_decode)(Decoder &decoder, Path path_fs); | ||||
| 	void (*file_decode)(DecoderClient &client, Path path_fs); | ||||
|  | ||||
| 	/** | ||||
| 	 * Scan metadata of a file. | ||||
| @@ -127,16 +122,16 @@ struct DecoderPlugin { | ||||
| 	/** | ||||
| 	 * Decode a stream. | ||||
| 	 */ | ||||
| 	void StreamDecode(Decoder &decoder, InputStream &is) const { | ||||
| 		stream_decode(decoder, is); | ||||
| 	void StreamDecode(DecoderClient &client, InputStream &is) const { | ||||
| 		stream_decode(client, is); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Decode a file. | ||||
| 	 */ | ||||
| 	template<typename P> | ||||
| 	void FileDecode(Decoder &decoder, P path_fs) const { | ||||
| 		file_decode(decoder, path_fs); | ||||
| 	void FileDecode(DecoderClient &client, P path_fs) const { | ||||
| 		file_decode(client, path_fs); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
|   | ||||
| @@ -24,5 +24,5 @@ | ||||
| size_t | ||||
| DecoderReader::Read(void *data, size_t size) | ||||
| { | ||||
| 	return decoder_read(&decoder, is, data, size); | ||||
| 	return decoder_read(client, is, data, size); | ||||
| } | ||||
|   | ||||
| @@ -24,7 +24,7 @@ | ||||
| #include "fs/io/Reader.hxx" | ||||
| #include "Compiler.h" | ||||
|  | ||||
| struct Decoder; | ||||
| class DecoderClient; | ||||
| class InputStream; | ||||
|  | ||||
| /** | ||||
| @@ -32,15 +32,15 @@ class InputStream; | ||||
|  * interface. | ||||
|  */ | ||||
| class DecoderReader final : public Reader { | ||||
| 	Decoder &decoder; | ||||
| 	DecoderClient &client; | ||||
| 	InputStream &is; | ||||
|  | ||||
| public: | ||||
| 	DecoderReader(Decoder &_decoder, InputStream &_is) | ||||
| 		:decoder(_decoder), is(_is) {} | ||||
| 	DecoderReader(DecoderClient &_client, InputStream &_is) | ||||
| 		:client(_client), is(_is) {} | ||||
|  | ||||
| 	Decoder &GetDecoder() { | ||||
| 		return decoder; | ||||
| 	DecoderClient &GetClient() { | ||||
| 		return client; | ||||
| 	} | ||||
|  | ||||
| 	InputStream &GetInputStream() { | ||||
|   | ||||
| @@ -49,7 +49,7 @@ adplug_init(const ConfigBlock &block) | ||||
| } | ||||
|  | ||||
| static void | ||||
| adplug_file_decode(Decoder &decoder, Path path_fs) | ||||
| adplug_file_decode(DecoderClient &client, Path path_fs) | ||||
| { | ||||
| 	CEmuopl opl(sample_rate, true, true); | ||||
| 	opl.init(); | ||||
| @@ -61,7 +61,7 @@ adplug_file_decode(Decoder &decoder, Path path_fs) | ||||
| 	const AudioFormat audio_format(sample_rate, SampleFormat::S16, 2); | ||||
| 	assert(audio_format.IsValid()); | ||||
|  | ||||
| 	decoder_initialized(decoder, audio_format, false, | ||||
| 	decoder_initialized(client, audio_format, false, | ||||
| 			    SongTime::FromMS(player->songlength())); | ||||
|  | ||||
| 	DecoderCommand cmd; | ||||
| @@ -73,7 +73,7 @@ adplug_file_decode(Decoder &decoder, Path path_fs) | ||||
| 		int16_t buffer[2048]; | ||||
| 		constexpr unsigned frames_per_buffer = ARRAY_SIZE(buffer) / 2; | ||||
| 		opl.update(buffer, frames_per_buffer); | ||||
| 		cmd = decoder_data(decoder, nullptr, | ||||
| 		cmd = decoder_data(client, nullptr, | ||||
| 				   buffer, sizeof(buffer), | ||||
| 				   0); | ||||
| 	} while (cmd == DecoderCommand::NONE); | ||||
|   | ||||
| @@ -51,14 +51,14 @@ audiofile_init(const ConfigBlock &) | ||||
| } | ||||
|  | ||||
| struct AudioFileInputStream { | ||||
| 	Decoder *const decoder; | ||||
| 	DecoderClient *const client; | ||||
| 	InputStream &is; | ||||
|  | ||||
| 	size_t Read(void *buffer, size_t size) { | ||||
| 		/* libaudiofile does not like partial reads at all, | ||||
| 		   and will abort playback; therefore always force full | ||||
| 		   reads */ | ||||
| 		return decoder_read_full(decoder, is, buffer, size) | ||||
| 		return decoder_read_full(client, is, buffer, size) | ||||
| 			? size | ||||
| 			: 0; | ||||
| 	} | ||||
| @@ -181,14 +181,14 @@ audiofile_setup_sample_format(AFfilehandle af_fp) | ||||
| } | ||||
|  | ||||
| static void | ||||
| audiofile_stream_decode(Decoder &decoder, InputStream &is) | ||||
| audiofile_stream_decode(DecoderClient &client, InputStream &is) | ||||
| { | ||||
| 	if (!is.IsSeekable() || !is.KnownSize()) { | ||||
| 		LogWarning(audiofile_domain, "not seekable"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	AudioFileInputStream afis{&decoder, is}; | ||||
| 	AudioFileInputStream afis{&client, is}; | ||||
| 	AFvirtualfile *const vf = setup_virtual_fops(afis); | ||||
|  | ||||
| 	const AFfilehandle fh = afOpenVirtualFile(vf, "r", nullptr); | ||||
| @@ -210,7 +210,7 @@ audiofile_stream_decode(Decoder &decoder, InputStream &is) | ||||
| 	const unsigned frame_size = (unsigned) | ||||
| 		afGetVirtualFrameSize(fh, AF_DEFAULT_TRACK, true); | ||||
|  | ||||
| 	decoder_initialized(decoder, audio_format, true, total_time); | ||||
| 	decoder_initialized(client, audio_format, true, total_time); | ||||
|  | ||||
| 	DecoderCommand cmd; | ||||
| 	do { | ||||
| @@ -223,15 +223,15 @@ audiofile_stream_decode(Decoder &decoder, InputStream &is) | ||||
| 		if (nframes <= 0) | ||||
| 			break; | ||||
|  | ||||
| 		cmd = decoder_data(decoder, nullptr, | ||||
| 		cmd = decoder_data(client, nullptr, | ||||
| 				   chunk, nframes * frame_size, | ||||
| 				   kbit_rate); | ||||
|  | ||||
| 		if (cmd == DecoderCommand::SEEK) { | ||||
| 			AFframecount frame = decoder_seek_where_frame(decoder); | ||||
| 			AFframecount frame = decoder_seek_where_frame(client); | ||||
| 			afSeekFrame(fh, AF_DEFAULT_TRACK, frame); | ||||
|  | ||||
| 			decoder_command_finished(decoder); | ||||
| 			decoder_command_finished(client); | ||||
| 			cmd = DecoderCommand::NONE; | ||||
| 		} | ||||
| 	} while (cmd == DecoderCommand::NONE); | ||||
|   | ||||
| @@ -51,7 +51,7 @@ DsdId::Equals(const char *s) const | ||||
|  * Skip the #InputStream to the specified offset. | ||||
|  */ | ||||
| bool | ||||
| dsdlib_skip_to(Decoder *decoder, InputStream &is, | ||||
| dsdlib_skip_to(DecoderClient *client, InputStream &is, | ||||
| 	       offset_type offset) | ||||
| { | ||||
| 	if (is.IsSeekable()) { | ||||
| @@ -65,14 +65,14 @@ dsdlib_skip_to(Decoder *decoder, InputStream &is, | ||||
| 	if (is.GetOffset() > offset) | ||||
| 		return false; | ||||
|  | ||||
| 	return dsdlib_skip(decoder, is, offset - is.GetOffset()); | ||||
| 	return dsdlib_skip(client, is, offset - is.GetOffset()); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Skip some bytes from the #InputStream. | ||||
|  */ | ||||
| bool | ||||
| dsdlib_skip(Decoder *decoder, InputStream &is, | ||||
| dsdlib_skip(DecoderClient *client, InputStream &is, | ||||
| 	    offset_type delta) | ||||
| { | ||||
| 	if (delta == 0) | ||||
| @@ -91,7 +91,7 @@ dsdlib_skip(Decoder *decoder, InputStream &is, | ||||
| 		   expensive */ | ||||
| 		return false; | ||||
|  | ||||
| 	return decoder_skip(decoder, is, delta); | ||||
| 	return decoder_skip(client, is, delta); | ||||
| } | ||||
|  | ||||
| bool | ||||
|   | ||||
| @@ -26,8 +26,8 @@ | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| struct Decoder; | ||||
| struct TagHandler; | ||||
| class DecoderClient; | ||||
| class InputStream; | ||||
|  | ||||
| struct DsdId { | ||||
| @@ -60,11 +60,11 @@ public: | ||||
| }; | ||||
|  | ||||
| bool | ||||
| dsdlib_skip_to(Decoder *decoder, InputStream &is, | ||||
| dsdlib_skip_to(DecoderClient *client, InputStream &is, | ||||
| 	       offset_type offset); | ||||
|  | ||||
| bool | ||||
| dsdlib_skip(Decoder *decoder, InputStream &is, | ||||
| dsdlib_skip(DecoderClient *client, InputStream &is, | ||||
| 	    offset_type delta); | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -78,21 +78,21 @@ dsdiff_init(const ConfigBlock &block) | ||||
| } | ||||
|  | ||||
| static bool | ||||
| dsdiff_read_id(Decoder *decoder, InputStream &is, | ||||
| dsdiff_read_id(DecoderClient *client, InputStream &is, | ||||
| 	       DsdId *id) | ||||
| { | ||||
| 	return decoder_read_full(decoder, is, id, sizeof(*id)); | ||||
| 	return decoder_read_full(client, is, id, sizeof(*id)); | ||||
| } | ||||
|  | ||||
| static bool | ||||
| dsdiff_read_chunk_header(Decoder *decoder, InputStream &is, | ||||
| dsdiff_read_chunk_header(DecoderClient *client, InputStream &is, | ||||
| 			 DsdiffChunkHeader *header) | ||||
| { | ||||
| 	return decoder_read_full(decoder, is, header, sizeof(*header)); | ||||
| 	return decoder_read_full(client, is, header, sizeof(*header)); | ||||
| } | ||||
|  | ||||
| static bool | ||||
| dsdiff_read_payload(Decoder *decoder, InputStream &is, | ||||
| dsdiff_read_payload(DecoderClient *client, InputStream &is, | ||||
| 		    const DsdiffChunkHeader *header, | ||||
| 		    void *data, size_t length) | ||||
| { | ||||
| @@ -100,20 +100,20 @@ dsdiff_read_payload(Decoder *decoder, InputStream &is, | ||||
| 	if (size != (uint64_t)length) | ||||
| 		return false; | ||||
|  | ||||
| 	return decoder_read_full(decoder, is, data, length); | ||||
| 	return decoder_read_full(client, is, data, length); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Read and parse a "SND" chunk inside "PROP". | ||||
|  */ | ||||
| static bool | ||||
| dsdiff_read_prop_snd(Decoder *decoder, InputStream &is, | ||||
| dsdiff_read_prop_snd(DecoderClient *client, InputStream &is, | ||||
| 		     DsdiffMetaData *metadata, | ||||
| 		     offset_type end_offset) | ||||
| { | ||||
| 	DsdiffChunkHeader header; | ||||
| 	while (is.GetOffset() + sizeof(header) <= end_offset) { | ||||
| 		if (!dsdiff_read_chunk_header(decoder, is, &header)) | ||||
| 		if (!dsdiff_read_chunk_header(client, is, &header)) | ||||
| 			return false; | ||||
|  | ||||
| 		offset_type chunk_end_offset = is.GetOffset() | ||||
| @@ -123,7 +123,7 @@ dsdiff_read_prop_snd(Decoder *decoder, InputStream &is, | ||||
|  | ||||
| 		if (header.id.Equals("FS  ")) { | ||||
| 			uint32_t sample_rate; | ||||
| 			if (!dsdiff_read_payload(decoder, is, &header, | ||||
| 			if (!dsdiff_read_payload(client, is, &header, | ||||
| 						 &sample_rate, | ||||
| 						 sizeof(sample_rate))) | ||||
| 				return false; | ||||
| @@ -132,18 +132,18 @@ dsdiff_read_prop_snd(Decoder *decoder, InputStream &is, | ||||
| 		} else if (header.id.Equals("CHNL")) { | ||||
| 			uint16_t channels; | ||||
| 			if (header.GetSize() < sizeof(channels) || | ||||
| 			    !decoder_read_full(decoder, is, | ||||
| 			    !decoder_read_full(client, is, | ||||
| 					       &channels, sizeof(channels)) || | ||||
| 			    !dsdlib_skip_to(decoder, is, chunk_end_offset)) | ||||
| 			    !dsdlib_skip_to(client, is, chunk_end_offset)) | ||||
| 				return false; | ||||
|  | ||||
| 			metadata->channels = FromBE16(channels); | ||||
| 		} else if (header.id.Equals("CMPR")) { | ||||
| 			DsdId type; | ||||
| 			if (header.GetSize() < sizeof(type) || | ||||
| 			    !decoder_read_full(decoder, is, | ||||
| 			    !decoder_read_full(client, is, | ||||
| 					       &type, sizeof(type)) || | ||||
| 			    !dsdlib_skip_to(decoder, is, chunk_end_offset)) | ||||
| 			    !dsdlib_skip_to(client, is, chunk_end_offset)) | ||||
| 				return false; | ||||
|  | ||||
| 			if (!type.Equals("DSD ")) | ||||
| @@ -153,7 +153,7 @@ dsdiff_read_prop_snd(Decoder *decoder, InputStream &is, | ||||
| 		} else { | ||||
| 			/* ignore unknown chunk */ | ||||
|  | ||||
| 			if (!dsdlib_skip_to(decoder, is, chunk_end_offset)) | ||||
| 			if (!dsdlib_skip_to(client, is, chunk_end_offset)) | ||||
| 				return false; | ||||
| 		} | ||||
| 	} | ||||
| @@ -165,7 +165,7 @@ dsdiff_read_prop_snd(Decoder *decoder, InputStream &is, | ||||
|  * Read and parse a "PROP" chunk. | ||||
|  */ | ||||
| static bool | ||||
| dsdiff_read_prop(Decoder *decoder, InputStream &is, | ||||
| dsdiff_read_prop(DecoderClient *client, InputStream &is, | ||||
| 		 DsdiffMetaData *metadata, | ||||
| 		 const DsdiffChunkHeader *prop_header) | ||||
| { | ||||
| @@ -174,14 +174,14 @@ dsdiff_read_prop(Decoder *decoder, InputStream &is, | ||||
|  | ||||
| 	DsdId prop_id; | ||||
| 	if (prop_size < sizeof(prop_id) || | ||||
| 	    !dsdiff_read_id(decoder, is, &prop_id)) | ||||
| 	    !dsdiff_read_id(client, is, &prop_id)) | ||||
| 		return false; | ||||
|  | ||||
| 	if (prop_id.Equals("SND ")) | ||||
| 		return dsdiff_read_prop_snd(decoder, is, metadata, end_offset); | ||||
| 		return dsdiff_read_prop_snd(client, is, metadata, end_offset); | ||||
| 	else | ||||
| 		/* ignore unknown PROP chunk */ | ||||
| 		return dsdlib_skip_to(decoder, is, end_offset); | ||||
| 		return dsdlib_skip_to(client, is, end_offset); | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -225,7 +225,7 @@ dsdiff_handle_native_tag(InputStream &is, | ||||
|  */ | ||||
|  | ||||
| static bool | ||||
| dsdiff_read_metadata_extra(Decoder *decoder, InputStream &is, | ||||
| dsdiff_read_metadata_extra(DecoderClient *client, InputStream &is, | ||||
| 			   DsdiffMetaData *metadata, | ||||
| 			   DsdiffChunkHeader *chunk_header, | ||||
| 			   const TagHandler &handler, | ||||
| @@ -233,9 +233,9 @@ dsdiff_read_metadata_extra(Decoder *decoder, InputStream &is, | ||||
| { | ||||
|  | ||||
| 	/* skip from DSD data to next chunk header */ | ||||
| 	if (!dsdlib_skip(decoder, is, metadata->chunk_size)) | ||||
| 	if (!dsdlib_skip(client, is, metadata->chunk_size)) | ||||
| 		return false; | ||||
| 	if (!dsdiff_read_chunk_header(decoder, is, chunk_header)) | ||||
| 	if (!dsdiff_read_chunk_header(client, is, chunk_header)) | ||||
| 		return false; | ||||
|  | ||||
| 	/** offset for artist tag */ | ||||
| @@ -276,9 +276,9 @@ dsdiff_read_metadata_extra(Decoder *decoder, InputStream &is, | ||||
| 		} | ||||
| #endif | ||||
|  | ||||
| 		if (!dsdlib_skip(decoder, is, chunk_size)) | ||||
| 		if (!dsdlib_skip(client, is, chunk_size)) | ||||
| 			break; | ||||
| 	} while (dsdiff_read_chunk_header(decoder, is, chunk_header)); | ||||
| 	} while (dsdiff_read_chunk_header(client, is, chunk_header)); | ||||
|  | ||||
| 	/* done processing chunk headers, process tags if any */ | ||||
|  | ||||
| @@ -307,23 +307,23 @@ dsdiff_read_metadata_extra(Decoder *decoder, InputStream &is, | ||||
|  * "chunk_header" parameter. | ||||
|  */ | ||||
| static bool | ||||
| dsdiff_read_metadata(Decoder *decoder, InputStream &is, | ||||
| dsdiff_read_metadata(DecoderClient *client, InputStream &is, | ||||
| 		     DsdiffMetaData *metadata, | ||||
| 		     DsdiffChunkHeader *chunk_header) | ||||
| { | ||||
| 	DsdiffHeader header; | ||||
| 	if (!decoder_read_full(decoder, is, &header, sizeof(header)) || | ||||
| 	if (!decoder_read_full(client, is, &header, sizeof(header)) || | ||||
| 	    !header.id.Equals("FRM8") || | ||||
| 	    !header.format.Equals("DSD ")) | ||||
| 		return false; | ||||
|  | ||||
| 	while (true) { | ||||
| 		if (!dsdiff_read_chunk_header(decoder, is, | ||||
| 		if (!dsdiff_read_chunk_header(client, is, | ||||
| 					      chunk_header)) | ||||
| 			return false; | ||||
|  | ||||
| 		if (chunk_header->id.Equals("PROP")) { | ||||
| 			if (!dsdiff_read_prop(decoder, is, metadata, | ||||
| 			if (!dsdiff_read_prop(client, is, metadata, | ||||
| 					      chunk_header)) | ||||
| 					return false; | ||||
| 		} else if (chunk_header->id.Equals("DSD ")) { | ||||
| @@ -336,7 +336,7 @@ dsdiff_read_metadata(Decoder *decoder, InputStream &is, | ||||
| 			const offset_type chunk_end_offset = | ||||
| 				is.GetOffset() + chunk_size; | ||||
|  | ||||
| 			if (!dsdlib_skip_to(decoder, is, chunk_end_offset)) | ||||
| 			if (!dsdlib_skip_to(client, is, chunk_end_offset)) | ||||
| 				return false; | ||||
| 		} | ||||
| 	} | ||||
| @@ -359,7 +359,7 @@ FrameToOffset(uint64_t frame, unsigned channels) | ||||
|  * Decode one "DSD" chunk. | ||||
|  */ | ||||
| static bool | ||||
| dsdiff_decode_chunk(Decoder &decoder, InputStream &is, | ||||
| dsdiff_decode_chunk(DecoderClient &client, InputStream &is, | ||||
| 		    unsigned channels, unsigned sample_rate, | ||||
| 		    const offset_type total_bytes) | ||||
| { | ||||
| @@ -372,23 +372,23 @@ dsdiff_decode_chunk(Decoder &decoder, InputStream &is, | ||||
| 	const unsigned buffer_frames = sizeof(buffer) / frame_size; | ||||
| 	const size_t buffer_size = buffer_frames * frame_size; | ||||
|  | ||||
| 	auto cmd = decoder_get_command(decoder); | ||||
| 	auto cmd = decoder_get_command(client); | ||||
| 	for (offset_type remaining_bytes = total_bytes; | ||||
| 	     remaining_bytes >= frame_size && cmd != DecoderCommand::STOP;) { | ||||
| 		if (cmd == DecoderCommand::SEEK) { | ||||
| 			uint64_t frame = decoder_seek_where_frame(decoder); | ||||
| 			uint64_t frame = decoder_seek_where_frame(client); | ||||
| 			offset_type offset = FrameToOffset(frame, channels); | ||||
| 			if (offset >= total_bytes) { | ||||
| 				decoder_command_finished(decoder); | ||||
| 				decoder_command_finished(client); | ||||
| 				break; | ||||
| 			} | ||||
|  | ||||
| 			if (dsdlib_skip_to(&decoder, is, | ||||
| 			if (dsdlib_skip_to(&client, is, | ||||
| 					   start_offset + offset)) { | ||||
| 				decoder_command_finished(decoder); | ||||
| 				decoder_command_finished(client); | ||||
| 				remaining_bytes = total_bytes - offset; | ||||
| 			} else | ||||
| 				decoder_seek_error(decoder); | ||||
| 				decoder_seek_error(client); | ||||
| 		} | ||||
|  | ||||
| 		/* see how much aligned data from the remaining chunk | ||||
| @@ -399,7 +399,7 @@ dsdiff_decode_chunk(Decoder &decoder, InputStream &is, | ||||
| 			now_size = now_frames * frame_size; | ||||
| 		} | ||||
|  | ||||
| 		if (!decoder_read_full(&decoder, is, buffer, now_size)) | ||||
| 		if (!decoder_read_full(&client, is, buffer, now_size)) | ||||
| 			return false; | ||||
|  | ||||
| 		const size_t nbytes = now_size; | ||||
| @@ -408,7 +408,7 @@ dsdiff_decode_chunk(Decoder &decoder, InputStream &is, | ||||
| 		if (lsbitfirst) | ||||
| 			bit_reverse_buffer(buffer, buffer + nbytes); | ||||
|  | ||||
| 		cmd = decoder_data(decoder, is, buffer, nbytes, | ||||
| 		cmd = decoder_data(client, is, buffer, nbytes, | ||||
| 				   sample_rate / 1000); | ||||
| 	} | ||||
|  | ||||
| @@ -416,13 +416,13 @@ dsdiff_decode_chunk(Decoder &decoder, InputStream &is, | ||||
| } | ||||
|  | ||||
| static void | ||||
| dsdiff_stream_decode(Decoder &decoder, InputStream &is) | ||||
| dsdiff_stream_decode(DecoderClient &client, InputStream &is) | ||||
| { | ||||
| 	DsdiffMetaData metadata; | ||||
|  | ||||
| 	DsdiffChunkHeader chunk_header; | ||||
| 	/* check if it is is a proper DFF file */ | ||||
| 	if (!dsdiff_read_metadata(&decoder, is, &metadata, &chunk_header)) | ||||
| 	if (!dsdiff_read_metadata(&client, is, &metadata, &chunk_header)) | ||||
| 		return; | ||||
|  | ||||
| 	auto audio_format = CheckAudioFormat(metadata.sample_rate / 8, | ||||
| @@ -437,12 +437,12 @@ dsdiff_stream_decode(Decoder &decoder, InputStream &is) | ||||
| 						      audio_format.sample_rate); | ||||
|  | ||||
| 	/* success: file was recognized */ | ||||
| 	decoder_initialized(decoder, audio_format, is.IsSeekable(), songtime); | ||||
| 	decoder_initialized(client, audio_format, is.IsSeekable(), songtime); | ||||
|  | ||||
| 	/* every iteration of the following loop decodes one "DSD" | ||||
| 	   chunk from a DFF file */ | ||||
|  | ||||
| 	dsdiff_decode_chunk(decoder, is, | ||||
| 	dsdiff_decode_chunk(client, is, | ||||
| 			    metadata.channels, | ||||
| 			    metadata.sample_rate, | ||||
| 			    chunk_size); | ||||
|   | ||||
| @@ -98,11 +98,11 @@ struct DsfDataChunk { | ||||
|  * Read and parse all needed metadata chunks for DSF files. | ||||
|  */ | ||||
| static bool | ||||
| dsf_read_metadata(Decoder *decoder, InputStream &is, | ||||
| dsf_read_metadata(DecoderClient *client, InputStream &is, | ||||
| 		  DsfMetaData *metadata) | ||||
| { | ||||
| 	DsfHeader dsf_header; | ||||
| 	if (!decoder_read_full(decoder, is, &dsf_header, sizeof(dsf_header)) || | ||||
| 	if (!decoder_read_full(client, is, &dsf_header, sizeof(dsf_header)) || | ||||
| 	    !dsf_header.id.Equals("DSD ")) | ||||
| 		return false; | ||||
|  | ||||
| @@ -116,7 +116,7 @@ dsf_read_metadata(Decoder *decoder, InputStream &is, | ||||
|  | ||||
| 	/* read the 'fmt ' chunk of the DSF file */ | ||||
| 	DsfFmtChunk dsf_fmt_chunk; | ||||
| 	if (!decoder_read_full(decoder, is, | ||||
| 	if (!decoder_read_full(client, is, | ||||
| 			       &dsf_fmt_chunk, sizeof(dsf_fmt_chunk)) || | ||||
| 	    !dsf_fmt_chunk.id.Equals("fmt ")) | ||||
| 		return false; | ||||
| @@ -144,7 +144,7 @@ dsf_read_metadata(Decoder *decoder, InputStream &is, | ||||
|  | ||||
| 	/* read the 'data' chunk of the DSF file */ | ||||
| 	DsfDataChunk data_chunk; | ||||
| 	if (!decoder_read_full(decoder, is, &data_chunk, sizeof(data_chunk)) || | ||||
| 	if (!decoder_read_full(client, is, &data_chunk, sizeof(data_chunk)) || | ||||
| 	    !data_chunk.id.Equals("data")) | ||||
| 		return false; | ||||
|  | ||||
| @@ -251,7 +251,7 @@ FrameToBlock(uint64_t frame) | ||||
|  * Decode one complete DSF 'data' chunk i.e. a complete song | ||||
|  */ | ||||
| static bool | ||||
| dsf_decode_chunk(Decoder &decoder, InputStream &is, | ||||
| dsf_decode_chunk(DecoderClient &client, InputStream &is, | ||||
| 		 unsigned channels, unsigned sample_rate, | ||||
| 		 offset_type n_blocks, | ||||
| 		 bool bitreverse) | ||||
| @@ -259,28 +259,28 @@ dsf_decode_chunk(Decoder &decoder, InputStream &is, | ||||
| 	const size_t block_size = channels * DSF_BLOCK_SIZE; | ||||
| 	const offset_type start_offset = is.GetOffset(); | ||||
|  | ||||
| 	auto cmd = decoder_get_command(decoder); | ||||
| 	auto cmd = decoder_get_command(client); | ||||
| 	for (offset_type i = 0; i < n_blocks && cmd != DecoderCommand::STOP;) { | ||||
| 		if (cmd == DecoderCommand::SEEK) { | ||||
| 			uint64_t frame = decoder_seek_where_frame(decoder); | ||||
| 			uint64_t frame = decoder_seek_where_frame(client); | ||||
| 			offset_type block = FrameToBlock(frame); | ||||
| 			if (block >= n_blocks) { | ||||
| 				decoder_command_finished(decoder); | ||||
| 				decoder_command_finished(client); | ||||
| 				break; | ||||
| 			} | ||||
|  | ||||
| 			offset_type offset = | ||||
| 				start_offset + block * block_size; | ||||
| 			if (dsdlib_skip_to(&decoder, is, offset)) { | ||||
| 				decoder_command_finished(decoder); | ||||
| 			if (dsdlib_skip_to(&client, is, offset)) { | ||||
| 				decoder_command_finished(client); | ||||
| 				i = block; | ||||
| 			} else | ||||
| 				decoder_seek_error(decoder); | ||||
| 				decoder_seek_error(client); | ||||
| 		} | ||||
|  | ||||
| 		/* worst-case buffer size */ | ||||
| 		uint8_t buffer[MAX_CHANNELS * DSF_BLOCK_SIZE]; | ||||
| 		if (!decoder_read_full(&decoder, is, buffer, block_size)) | ||||
| 		if (!decoder_read_full(&client, is, buffer, block_size)) | ||||
| 			return false; | ||||
|  | ||||
| 		if (bitreverse) | ||||
| @@ -289,7 +289,7 @@ dsf_decode_chunk(Decoder &decoder, InputStream &is, | ||||
| 		uint8_t interleaved_buffer[MAX_CHANNELS * DSF_BLOCK_SIZE]; | ||||
| 		InterleaveDsfBlock(interleaved_buffer, buffer, channels); | ||||
|  | ||||
| 		cmd = decoder_data(decoder, is, | ||||
| 		cmd = decoder_data(client, is, | ||||
| 				   interleaved_buffer, block_size, | ||||
| 				   sample_rate / 1000); | ||||
| 		++i; | ||||
| @@ -299,11 +299,11 @@ dsf_decode_chunk(Decoder &decoder, InputStream &is, | ||||
| } | ||||
|  | ||||
| static void | ||||
| dsf_stream_decode(Decoder &decoder, InputStream &is) | ||||
| dsf_stream_decode(DecoderClient &client, InputStream &is) | ||||
| { | ||||
| 	/* check if it is a proper DSF file */ | ||||
| 	DsfMetaData metadata; | ||||
| 	if (!dsf_read_metadata(&decoder, is, &metadata)) | ||||
| 	if (!dsf_read_metadata(&client, is, &metadata)) | ||||
| 		return; | ||||
|  | ||||
| 	auto audio_format = CheckAudioFormat(metadata.sample_rate / 8, | ||||
| @@ -316,9 +316,9 @@ dsf_stream_decode(Decoder &decoder, InputStream &is) | ||||
| 						      audio_format.sample_rate); | ||||
|  | ||||
| 	/* success: file was recognized */ | ||||
| 	decoder_initialized(decoder, audio_format, is.IsSeekable(), songtime); | ||||
| 	decoder_initialized(client, audio_format, is.IsSeekable(), songtime); | ||||
|  | ||||
| 	dsf_decode_chunk(decoder, is, metadata.channels, | ||||
| 	dsf_decode_chunk(client, is, metadata.channels, | ||||
| 			 metadata.sample_rate, | ||||
| 			 n_blocks, | ||||
| 			 metadata.bitreverse); | ||||
|   | ||||
| @@ -324,7 +324,7 @@ faad_get_file_time(InputStream &is) | ||||
| } | ||||
|  | ||||
| static void | ||||
| faad_stream_decode(Decoder &mpd_decoder, InputStream &is, | ||||
| faad_stream_decode(DecoderClient &client, InputStream &is, | ||||
| 		   DecoderBuffer &buffer, const NeAACDecHandle decoder) | ||||
| { | ||||
| 	const auto total_time = faad_song_duration(buffer, is); | ||||
| @@ -339,7 +339,7 @@ faad_stream_decode(Decoder &mpd_decoder, InputStream &is, | ||||
|  | ||||
| 	/* initialize the MPD core */ | ||||
|  | ||||
| 	decoder_initialized(mpd_decoder, audio_format, false, total_time); | ||||
| 	decoder_initialized(client, audio_format, false, total_time); | ||||
|  | ||||
| 	/* the decoder loop */ | ||||
|  | ||||
| @@ -393,16 +393,16 @@ faad_stream_decode(Decoder &mpd_decoder, InputStream &is, | ||||
|  | ||||
| 		/* send PCM samples to MPD */ | ||||
|  | ||||
| 		cmd = decoder_data(mpd_decoder, is, decoded, | ||||
| 		cmd = decoder_data(client, is, decoded, | ||||
| 				   (size_t)frame_info.samples * 2, | ||||
| 				   bit_rate); | ||||
| 	} while (cmd != DecoderCommand::STOP); | ||||
| } | ||||
|  | ||||
| static void | ||||
| faad_stream_decode(Decoder &mpd_decoder, InputStream &is) | ||||
| faad_stream_decode(DecoderClient &client, InputStream &is) | ||||
| { | ||||
| 	DecoderBuffer buffer(&mpd_decoder, is, | ||||
| 	DecoderBuffer buffer(&client, is, | ||||
| 			     FAAD_MIN_STREAMSIZE * MAX_CHANNELS); | ||||
|  | ||||
| 	/* create the libfaad decoder */ | ||||
| @@ -410,7 +410,7 @@ faad_stream_decode(Decoder &mpd_decoder, InputStream &is) | ||||
| 	const NeAACDecHandle decoder = faad_decoder_new(); | ||||
| 	AtScopeExit(decoder) { NeAACDecClose(decoder); }; | ||||
|  | ||||
| 	faad_stream_decode(mpd_decoder, is, buffer, decoder); | ||||
| 	faad_stream_decode(client, is, buffer, decoder); | ||||
| } | ||||
|  | ||||
| static bool | ||||
|   | ||||
| @@ -221,7 +221,7 @@ PtsToPcmFrame(uint64_t pts, const AVStream &stream, | ||||
|  * Invoke decoder_data() with the contents of an #AVFrame. | ||||
|  */ | ||||
| static DecoderCommand | ||||
| FfmpegSendFrame(Decoder &decoder, InputStream &is, | ||||
| FfmpegSendFrame(DecoderClient &client, InputStream &is, | ||||
| 		AVCodecContext &codec_context, | ||||
| 		const AVFrame &frame, | ||||
| 		size_t &skip_bytes, | ||||
| @@ -250,7 +250,7 @@ FfmpegSendFrame(Decoder &decoder, InputStream &is, | ||||
| 		skip_bytes = 0; | ||||
| 	} | ||||
|  | ||||
| 	return decoder_data(decoder, is, | ||||
| 	return decoder_data(client, is, | ||||
| 			    output_buffer.data, output_buffer.size, | ||||
| 			    codec_context.bit_rate / 1000); | ||||
| } | ||||
| @@ -258,7 +258,7 @@ FfmpegSendFrame(Decoder &decoder, InputStream &is, | ||||
| #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 0) | ||||
|  | ||||
| static DecoderCommand | ||||
| FfmpegReceiveFrames(Decoder &decoder, InputStream &is, | ||||
| FfmpegReceiveFrames(DecoderClient &client, InputStream &is, | ||||
| 		    AVCodecContext &codec_context, | ||||
| 		    AVFrame &frame, | ||||
| 		    size_t &skip_bytes, | ||||
| @@ -271,7 +271,7 @@ FfmpegReceiveFrames(Decoder &decoder, InputStream &is, | ||||
| 		int err = avcodec_receive_frame(&codec_context, &frame); | ||||
| 		switch (err) { | ||||
| 		case 0: | ||||
| 			cmd = FfmpegSendFrame(decoder, is, codec_context, | ||||
| 			cmd = FfmpegSendFrame(client, is, codec_context, | ||||
| 					      frame, skip_bytes, | ||||
| 					      buffer); | ||||
| 			if (cmd != DecoderCommand::NONE) | ||||
| @@ -312,7 +312,7 @@ FfmpegReceiveFrames(Decoder &decoder, InputStream &is, | ||||
|  * desired time stamp has been reached | ||||
|  */ | ||||
| static DecoderCommand | ||||
| ffmpeg_send_packet(Decoder &decoder, InputStream &is, | ||||
| ffmpeg_send_packet(DecoderClient &client, InputStream &is, | ||||
| 		   AVPacket &&packet, | ||||
| 		   AVCodecContext &codec_context, | ||||
| 		   const AVStream &stream, | ||||
| @@ -330,7 +330,7 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is, | ||||
| 			if (cur_frame < min_frame) | ||||
| 				skip_bytes = pcm_frame_size * (min_frame - cur_frame); | ||||
| 		} else | ||||
| 			decoder_timestamp(decoder, | ||||
| 			decoder_timestamp(client, | ||||
| 					  FfmpegTimeToDouble(pts, | ||||
| 							     stream.time_base)); | ||||
| 	} | ||||
| @@ -358,7 +358,7 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is, | ||||
| 		return DecoderCommand::NONE; | ||||
| 	} | ||||
|  | ||||
| 	auto cmd = FfmpegReceiveFrames(decoder, is, codec_context, | ||||
| 	auto cmd = FfmpegReceiveFrames(client, is, codec_context, | ||||
| 				       frame, | ||||
| 				       skip_bytes, buffer, eof); | ||||
|  | ||||
| @@ -383,7 +383,7 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is, | ||||
| 		if (!got_frame || frame.nb_samples <= 0) | ||||
| 			continue; | ||||
|  | ||||
| 		cmd = FfmpegSendFrame(decoder, is, codec_context, | ||||
| 		cmd = FfmpegSendFrame(client, is, codec_context, | ||||
| 				      frame, skip_bytes, | ||||
| 				      buffer); | ||||
| 	} | ||||
| @@ -393,7 +393,7 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is, | ||||
| } | ||||
|  | ||||
| static DecoderCommand | ||||
| ffmpeg_send_packet(Decoder &decoder, InputStream &is, | ||||
| ffmpeg_send_packet(DecoderClient &client, InputStream &is, | ||||
| 		   const AVPacket &packet, | ||||
| 		   AVCodecContext &codec_context, | ||||
| 		   const AVStream &stream, | ||||
| @@ -401,7 +401,7 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is, | ||||
| 		   uint64_t min_frame, size_t pcm_frame_size, | ||||
| 		   FfmpegBuffer &buffer) | ||||
| { | ||||
| 	return ffmpeg_send_packet(decoder, is, | ||||
| 	return ffmpeg_send_packet(client, is, | ||||
| 				  /* copy the AVPacket, because FFmpeg | ||||
| 				     < 3.0 requires this */ | ||||
| 				  AVPacket(packet), | ||||
| @@ -446,13 +446,13 @@ ffmpeg_sample_format(enum AVSampleFormat sample_fmt) | ||||
| } | ||||
|  | ||||
| static AVInputFormat * | ||||
| ffmpeg_probe(Decoder *decoder, InputStream &is) | ||||
| ffmpeg_probe(DecoderClient *client, InputStream &is) | ||||
| { | ||||
| 	constexpr size_t BUFFER_SIZE = 16384; | ||||
| 	constexpr size_t PADDING = 16; | ||||
|  | ||||
| 	unsigned char buffer[BUFFER_SIZE]; | ||||
| 	size_t nbytes = decoder_read(decoder, is, buffer, BUFFER_SIZE); | ||||
| 	size_t nbytes = decoder_read(client, is, buffer, BUFFER_SIZE); | ||||
| 	if (nbytes <= PADDING) | ||||
| 		return nullptr; | ||||
|  | ||||
| @@ -528,7 +528,7 @@ FfmpegParseMetaData(const AVFormatContext &format_context, int audio_stream, | ||||
| } | ||||
|  | ||||
| static void | ||||
| FfmpegParseMetaData(Decoder &decoder, | ||||
| FfmpegParseMetaData(DecoderClient &client, | ||||
| 		    const AVFormatContext &format_context, int audio_stream) | ||||
| { | ||||
| 	ReplayGainInfo rg; | ||||
| @@ -540,10 +540,10 @@ FfmpegParseMetaData(Decoder &decoder, | ||||
| 	FfmpegParseMetaData(format_context, audio_stream, rg, mr); | ||||
|  | ||||
| 	if (rg.IsDefined()) | ||||
| 		decoder_replay_gain(decoder, &rg); | ||||
| 		decoder_replay_gain(client, &rg); | ||||
|  | ||||
| 	if (mr.IsDefined()) | ||||
| 		decoder_mixramp(decoder, std::move(mr)); | ||||
| 		decoder_mixramp(client, std::move(mr)); | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -579,7 +579,7 @@ FfmpegScanTag(const AVFormatContext &format_context, int audio_stream, | ||||
|  * decoder_tag(). | ||||
|  */ | ||||
| static void | ||||
| FfmpegCheckTag(Decoder &decoder, InputStream &is, | ||||
| FfmpegCheckTag(DecoderClient &client, InputStream &is, | ||||
| 	       AVFormatContext &format_context, int audio_stream) | ||||
| { | ||||
| 	AVStream &stream = *format_context.streams[audio_stream]; | ||||
| @@ -593,13 +593,13 @@ FfmpegCheckTag(Decoder &decoder, InputStream &is, | ||||
| 	TagBuilder tag; | ||||
| 	FfmpegScanTag(format_context, audio_stream, tag); | ||||
| 	if (!tag.IsEmpty()) | ||||
| 		decoder_tag(decoder, is, tag.Commit()); | ||||
| 		decoder_tag(client, is, tag.Commit()); | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| static void | ||||
| FfmpegDecode(Decoder &decoder, InputStream &input, | ||||
| FfmpegDecode(DecoderClient &client, InputStream &input, | ||||
| 	     AVFormatContext &format_context) | ||||
| { | ||||
| 	const int find_result = | ||||
| @@ -689,10 +689,10 @@ FfmpegDecode(Decoder &decoder, InputStream &input, | ||||
| 	const SignedSongTime total_time = | ||||
| 		FromFfmpegTimeChecked(av_stream.duration, av_stream.time_base); | ||||
|  | ||||
| 	decoder_initialized(decoder, audio_format, | ||||
| 	decoder_initialized(client, audio_format, | ||||
| 			    input.IsSeekable(), total_time); | ||||
|  | ||||
| 	FfmpegParseMetaData(decoder, format_context, audio_stream); | ||||
| 	FfmpegParseMetaData(client, format_context, audio_stream); | ||||
|  | ||||
| #if LIBAVUTIL_VERSION_MAJOR >= 53 | ||||
| 	AVFrame *frame = av_frame_alloc(); | ||||
| @@ -718,11 +718,11 @@ FfmpegDecode(Decoder &decoder, InputStream &input, | ||||
|  | ||||
| 	uint64_t min_frame = 0; | ||||
|  | ||||
| 	DecoderCommand cmd = decoder_get_command(decoder); | ||||
| 	DecoderCommand cmd = decoder_get_command(client); | ||||
| 	while (cmd != DecoderCommand::STOP) { | ||||
| 		if (cmd == DecoderCommand::SEEK) { | ||||
| 			int64_t where = | ||||
| 				ToFfmpegTime(decoder_seek_time(decoder), | ||||
| 				ToFfmpegTime(decoder_seek_time(client), | ||||
| 					     av_stream.time_base) + | ||||
| 				start_time_fallback(av_stream); | ||||
|  | ||||
| @@ -731,11 +731,11 @@ FfmpegDecode(Decoder &decoder, InputStream &input, | ||||
| 			   stamp, not after */ | ||||
| 			if (av_seek_frame(&format_context, audio_stream, where, | ||||
| 					  AVSEEK_FLAG_ANY|AVSEEK_FLAG_BACKWARD) < 0) | ||||
| 				decoder_seek_error(decoder); | ||||
| 				decoder_seek_error(client); | ||||
| 			else { | ||||
| 				avcodec_flush_buffers(codec_context); | ||||
| 				min_frame = decoder_seek_where_frame(decoder); | ||||
| 				decoder_command_finished(decoder); | ||||
| 				min_frame = decoder_seek_where_frame(client); | ||||
| 				decoder_command_finished(client); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @@ -745,11 +745,11 @@ FfmpegDecode(Decoder &decoder, InputStream &input, | ||||
| 			break; | ||||
|  | ||||
| #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(56, 1, 0) | ||||
| 		FfmpegCheckTag(decoder, input, format_context, audio_stream); | ||||
| 		FfmpegCheckTag(client, input, format_context, audio_stream); | ||||
| #endif | ||||
|  | ||||
| 		if (packet.size > 0 && packet.stream_index == audio_stream) { | ||||
| 			cmd = ffmpeg_send_packet(decoder, input, | ||||
| 			cmd = ffmpeg_send_packet(client, input, | ||||
| 						 packet, | ||||
| 						 *codec_context, | ||||
| 						 av_stream, | ||||
| @@ -758,7 +758,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input, | ||||
| 						 interleaved_buffer); | ||||
| 			min_frame = 0; | ||||
| 		} else | ||||
| 			cmd = decoder_get_command(decoder); | ||||
| 			cmd = decoder_get_command(client); | ||||
|  | ||||
| #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 25, 100) | ||||
| 		av_packet_unref(&packet); | ||||
| @@ -769,16 +769,16 @@ FfmpegDecode(Decoder &decoder, InputStream &input, | ||||
| } | ||||
|  | ||||
| static void | ||||
| ffmpeg_decode(Decoder &decoder, InputStream &input) | ||||
| ffmpeg_decode(DecoderClient &client, InputStream &input) | ||||
| { | ||||
| 	AVInputFormat *input_format = ffmpeg_probe(&decoder, input); | ||||
| 	AVInputFormat *input_format = ffmpeg_probe(&client, input); | ||||
| 	if (input_format == nullptr) | ||||
| 		return; | ||||
|  | ||||
| 	FormatDebug(ffmpeg_domain, "detected input format '%s' (%s)", | ||||
| 		    input_format->name, input_format->long_name); | ||||
|  | ||||
| 	AvioStream stream(&decoder, input); | ||||
| 	AvioStream stream(&client, input); | ||||
| 	if (!stream.Open()) { | ||||
| 		LogError(ffmpeg_domain, "Failed to open stream"); | ||||
| 		return; | ||||
| @@ -797,7 +797,7 @@ ffmpeg_decode(Decoder &decoder, InputStream &input) | ||||
| 		avformat_close_input(&format_context); | ||||
| 	}; | ||||
|  | ||||
| 	FfmpegDecode(decoder, input, *format_context); | ||||
| 	FfmpegDecode(client, input, *format_context); | ||||
| } | ||||
|  | ||||
| static bool | ||||
|   | ||||
| @@ -38,7 +38,7 @@ AvioStream::~AvioStream() | ||||
| inline int | ||||
| AvioStream::Read(void *dest, int size) | ||||
| { | ||||
| 	return decoder_read(decoder, input, dest, size); | ||||
| 	return decoder_read(client, input, dest, size); | ||||
| } | ||||
|  | ||||
| inline int64_t | ||||
|   | ||||
| @@ -28,17 +28,17 @@ extern "C" { | ||||
|  | ||||
| #include <stdint.h> | ||||
|  | ||||
| class DecoderClient; | ||||
| class InputStream; | ||||
| struct Decoder; | ||||
|  | ||||
| struct AvioStream { | ||||
| 	Decoder *const decoder; | ||||
| 	DecoderClient *const client; | ||||
| 	InputStream &input; | ||||
|  | ||||
| 	AVIOContext *io; | ||||
|  | ||||
| 	AvioStream(Decoder *_decoder, InputStream &_input) | ||||
| 		:decoder(_decoder), input(_input), io(nullptr) {} | ||||
| 	AvioStream(DecoderClient *_client, InputStream &_input) | ||||
| 		:client(_client), input(_input), io(nullptr) {} | ||||
|  | ||||
| 	~AvioStream(); | ||||
|  | ||||
|   | ||||
| @@ -52,7 +52,7 @@ FlacDecoder::Initialize(unsigned sample_rate, unsigned bits_per_sample, | ||||
| 						      audio_format.sample_rate) | ||||
| 		: SignedSongTime::Negative(); | ||||
|  | ||||
| 	decoder_initialized(*GetDecoder(), audio_format, | ||||
| 	decoder_initialized(*GetClient(), audio_format, | ||||
| 			    GetInputStream().IsSeekable(), | ||||
| 			    duration); | ||||
|  | ||||
| @@ -77,9 +77,9 @@ FlacDecoder::OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc) | ||||
| { | ||||
| 	ReplayGainInfo rgi; | ||||
| 	if (flac_parse_replay_gain(rgi, vc)) | ||||
| 		decoder_replay_gain(*GetDecoder(), &rgi); | ||||
| 		decoder_replay_gain(*GetClient(), &rgi); | ||||
|  | ||||
| 	decoder_mixramp(*GetDecoder(), flac_parse_mixramp(vc)); | ||||
| 	decoder_mixramp(*GetClient(), flac_parse_mixramp(vc)); | ||||
|  | ||||
| 	tag = flac_vorbis_comments_to_tag(&vc); | ||||
| } | ||||
| @@ -148,7 +148,7 @@ FlacDecoder::OnWrite(const FLAC__Frame &frame, | ||||
| 	unsigned bit_rate = nbytes * 8 * frame.header.sample_rate / | ||||
| 		(1000 * frame.header.blocksize); | ||||
|  | ||||
| 	auto cmd = decoder_data(*GetDecoder(), GetInputStream(), | ||||
| 	auto cmd = decoder_data(*GetClient(), GetInputStream(), | ||||
| 				data.data, data.size, | ||||
| 				bit_rate); | ||||
| 	switch (cmd) { | ||||
|   | ||||
| @@ -51,8 +51,8 @@ struct FlacDecoder : public FlacInput { | ||||
|  | ||||
| 	Tag tag; | ||||
|  | ||||
| 	FlacDecoder(Decoder &_decoder, InputStream &_input_stream) | ||||
| 		:FlacInput(_input_stream, &_decoder) {} | ||||
| 	FlacDecoder(DecoderClient &_client, InputStream &_input_stream) | ||||
| 		:FlacInput(_input_stream, &_client) {} | ||||
|  | ||||
| 	/** | ||||
| 	 * Wrapper for decoder_initialized(). | ||||
|   | ||||
| @@ -142,25 +142,25 @@ flac_decoder_initialize(FlacDecoder *data, FLAC__StreamDecoder *sd) | ||||
| static void | ||||
| flac_decoder_loop(FlacDecoder *data, FLAC__StreamDecoder *flac_dec) | ||||
| { | ||||
| 	Decoder &decoder = *data->GetDecoder(); | ||||
| 	DecoderClient &client = *data->GetClient(); | ||||
|  | ||||
| 	while (true) { | ||||
| 		DecoderCommand cmd; | ||||
| 		if (!data->tag.IsEmpty()) { | ||||
| 			cmd = decoder_tag(decoder, data->GetInputStream(), | ||||
| 			cmd = decoder_tag(client, data->GetInputStream(), | ||||
| 					  std::move(data->tag)); | ||||
| 			data->tag.Clear(); | ||||
| 		} else | ||||
| 			cmd = decoder_get_command(decoder); | ||||
| 			cmd = decoder_get_command(client); | ||||
|  | ||||
| 		if (cmd == DecoderCommand::SEEK) { | ||||
| 			FLAC__uint64 seek_sample = | ||||
| 				decoder_seek_where_frame(decoder); | ||||
| 				decoder_seek_where_frame(client); | ||||
| 			if (FLAC__stream_decoder_seek_absolute(flac_dec, seek_sample)) { | ||||
| 				data->position = 0; | ||||
| 				decoder_command_finished(decoder); | ||||
| 				decoder_command_finished(client); | ||||
| 			} else | ||||
| 				decoder_seek_error(decoder); | ||||
| 				decoder_seek_error(client); | ||||
| 		} else if (cmd == DecoderCommand::STOP) | ||||
| 			break; | ||||
|  | ||||
| @@ -198,7 +198,7 @@ flac_decoder_loop(FlacDecoder *data, FLAC__StreamDecoder *flac_dec) | ||||
| 		} | ||||
|  | ||||
| 		if (!FLAC__stream_decoder_process_single(flac_dec) && | ||||
| 		    decoder_get_command(decoder) == DecoderCommand::NONE) { | ||||
| 		    decoder_get_command(client) == DecoderCommand::NONE) { | ||||
| 			/* a failure that was not triggered by a | ||||
| 			   decoder command */ | ||||
| 			flacPrintErroredState(FLAC__stream_decoder_get_state(flac_dec)); | ||||
| @@ -264,7 +264,7 @@ FlacInitAndDecode(FlacDecoder &data, FLAC__StreamDecoder *sd, bool is_ogg) | ||||
| } | ||||
|  | ||||
| static void | ||||
| flac_decode_internal(Decoder &decoder, | ||||
| flac_decode_internal(DecoderClient &client, | ||||
| 		     InputStream &input_stream, | ||||
| 		     bool is_ogg) | ||||
| { | ||||
| @@ -272,15 +272,15 @@ flac_decode_internal(Decoder &decoder, | ||||
| 	if (!flac_dec) | ||||
| 		return; | ||||
|  | ||||
| 	FlacDecoder data(decoder, input_stream); | ||||
| 	FlacDecoder data(client, input_stream); | ||||
|  | ||||
| 	FlacInitAndDecode(data, flac_dec.get(), is_ogg); | ||||
| } | ||||
|  | ||||
| static void | ||||
| flac_decode(Decoder &decoder, InputStream &input_stream) | ||||
| flac_decode(DecoderClient &client, InputStream &input_stream) | ||||
| { | ||||
| 	flac_decode_internal(decoder, input_stream, false); | ||||
| 	flac_decode_internal(client, input_stream, false); | ||||
| } | ||||
|  | ||||
| static bool | ||||
| @@ -322,9 +322,9 @@ oggflac_scan_stream(InputStream &is, | ||||
| } | ||||
|  | ||||
| static void | ||||
| oggflac_decode(Decoder &decoder, InputStream &input_stream) | ||||
| oggflac_decode(DecoderClient &client, InputStream &input_stream) | ||||
| { | ||||
| 	if (ogg_codec_detect(&decoder, input_stream) != OGG_CODEC_FLAC) | ||||
| 	if (ogg_codec_detect(&client, input_stream) != OGG_CODEC_FLAC) | ||||
| 		return; | ||||
|  | ||||
| 	/* rewind the stream, because ogg_codec_detect() has | ||||
| @@ -334,7 +334,7 @@ oggflac_decode(Decoder &decoder, InputStream &input_stream) | ||||
| 	} catch (const std::runtime_error &) { | ||||
| 	} | ||||
|  | ||||
| 	flac_decode_internal(decoder, input_stream, true); | ||||
| 	flac_decode_internal(client, input_stream, true); | ||||
| } | ||||
|  | ||||
| static const char *const oggflac_suffixes[] = { "ogg", "oga", nullptr }; | ||||
|   | ||||
| @@ -30,13 +30,13 @@ | ||||
| FLAC__StreamDecoderReadStatus | ||||
| FlacInput::Read(FLAC__byte buffer[], size_t *bytes) | ||||
| { | ||||
| 	size_t r = decoder_read(decoder, input_stream, (void *)buffer, *bytes); | ||||
| 	size_t r = decoder_read(client, input_stream, (void *)buffer, *bytes); | ||||
| 	*bytes = r; | ||||
|  | ||||
| 	if (r == 0) { | ||||
| 		if (input_stream.LockIsEOF() || | ||||
| 		    (decoder != nullptr && | ||||
| 		     decoder_get_command(*decoder) != DecoderCommand::NONE)) | ||||
| 		    (client != nullptr && | ||||
| 		     decoder_get_command(*client) != DecoderCommand::NONE)) | ||||
| 			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; | ||||
| 		else | ||||
| 			return FLAC__STREAM_DECODER_READ_STATUS_ABORT; | ||||
| @@ -83,17 +83,17 @@ FlacInput::Length(FLAC__uint64 *stream_length) | ||||
| FLAC__bool | ||||
| FlacInput::Eof() | ||||
| { | ||||
| 	return (decoder != nullptr && | ||||
| 		decoder_get_command(*decoder) != DecoderCommand::NONE && | ||||
| 		decoder_get_command(*decoder) != DecoderCommand::SEEK) || | ||||
| 	return (client != nullptr && | ||||
| 		decoder_get_command(*client) != DecoderCommand::NONE && | ||||
| 		decoder_get_command(*client) != DecoderCommand::SEEK) || | ||||
| 		input_stream.LockIsEOF(); | ||||
| } | ||||
|  | ||||
| void | ||||
| FlacInput::Error(FLAC__StreamDecoderErrorStatus status) | ||||
| { | ||||
| 	if (decoder == nullptr || | ||||
| 	    decoder_get_command(*decoder) != DecoderCommand::STOP) | ||||
| 	if (client == nullptr || | ||||
| 	    decoder_get_command(*client) != DecoderCommand::STOP) | ||||
| 		LogWarning(flac_domain, | ||||
| 			   FLAC__StreamDecoderErrorStatusString[status]); | ||||
| } | ||||
|   | ||||
| @@ -22,7 +22,7 @@ | ||||
|  | ||||
| #include <FLAC/stream_decoder.h> | ||||
|  | ||||
| struct Decoder; | ||||
| class DecoderClient; | ||||
| class InputStream; | ||||
|  | ||||
| /** | ||||
| @@ -30,17 +30,17 @@ class InputStream; | ||||
|  * callbacks. | ||||
|  */ | ||||
| class FlacInput { | ||||
| 	Decoder *const decoder; | ||||
| 	DecoderClient *const client; | ||||
|  | ||||
| 	InputStream &input_stream; | ||||
|  | ||||
| public: | ||||
| 	FlacInput(InputStream &_input_stream, | ||||
| 		  Decoder *_decoder=nullptr) | ||||
| 		:decoder(_decoder), input_stream(_input_stream) {} | ||||
| 		  DecoderClient *_client=nullptr) | ||||
| 		:client(_client), input_stream(_input_stream) {} | ||||
|  | ||||
| 	Decoder *GetDecoder() { | ||||
| 		return decoder; | ||||
| 	DecoderClient *GetClient() { | ||||
| 		return client; | ||||
| 	} | ||||
|  | ||||
| 	InputStream &GetInputStream() { | ||||
|   | ||||
| @@ -87,7 +87,7 @@ fluidsynth_init(const ConfigBlock &block) | ||||
| } | ||||
|  | ||||
| static void | ||||
| fluidsynth_file_decode(Decoder &decoder, Path path_fs) | ||||
| fluidsynth_file_decode(DecoderClient &client, Path path_fs) | ||||
| { | ||||
| 	char setting_sample_rate[] = "synth.sample-rate"; | ||||
| 	/* | ||||
| @@ -160,7 +160,7 @@ fluidsynth_file_decode(Decoder &decoder, Path path_fs) | ||||
| 	   MPD core */ | ||||
|  | ||||
| 	const AudioFormat audio_format(sample_rate, SampleFormat::S16, 2); | ||||
| 	decoder_initialized(decoder, audio_format, false, | ||||
| 	decoder_initialized(client, audio_format, false, | ||||
| 			    SignedSongTime::Negative()); | ||||
|  | ||||
| 	DecoderCommand cmd; | ||||
| @@ -177,7 +177,7 @@ fluidsynth_file_decode(Decoder &decoder, Path path_fs) | ||||
| 		if (ret != 0) | ||||
| 			break; | ||||
|  | ||||
| 		cmd = decoder_data(decoder, nullptr, buffer, sizeof(buffer), | ||||
| 		cmd = decoder_data(client, nullptr, buffer, sizeof(buffer), | ||||
| 				   0); | ||||
| 		if (cmd != DecoderCommand::NONE) | ||||
| 			break; | ||||
|   | ||||
| @@ -129,7 +129,7 @@ gme_container_scan(Path path_fs, const unsigned int tnum) | ||||
| } | ||||
|  | ||||
| static void | ||||
| gme_file_decode(Decoder &decoder, Path path_fs) | ||||
| gme_file_decode(DecoderClient &client, Path path_fs) | ||||
| { | ||||
| 	const auto container = ParseContainerPath(path_fs); | ||||
|  | ||||
| @@ -171,7 +171,7 @@ gme_file_decode(Decoder &decoder, Path path_fs) | ||||
| 						   SampleFormat::S16, | ||||
| 						   GME_CHANNELS); | ||||
|  | ||||
| 	decoder_initialized(decoder, audio_format, true, song_len); | ||||
| 	decoder_initialized(client, audio_format, true, song_len); | ||||
|  | ||||
| 	gme_err = gme_start_track(emu, container.track); | ||||
| 	if (gme_err != nullptr) | ||||
| @@ -190,15 +190,15 @@ gme_file_decode(Decoder &decoder, Path path_fs) | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		cmd = decoder_data(decoder, nullptr, buf, sizeof(buf), 0); | ||||
| 		cmd = decoder_data(client, nullptr, buf, sizeof(buf), 0); | ||||
| 		if (cmd == DecoderCommand::SEEK) { | ||||
| 			unsigned where = decoder_seek_time(decoder).ToMS(); | ||||
| 			unsigned where = decoder_seek_time(client).ToMS(); | ||||
| 			gme_err = gme_seek(emu, where); | ||||
| 			if (gme_err != nullptr) { | ||||
| 				LogWarning(gme_domain, gme_err); | ||||
| 				decoder_seek_error(decoder); | ||||
| 				decoder_seek_error(client); | ||||
| 			} else | ||||
| 				decoder_command_finished(decoder); | ||||
| 				decoder_command_finished(client); | ||||
| 		} | ||||
|  | ||||
| 		if (gme_track_ended(emu)) | ||||
|   | ||||
| @@ -141,11 +141,11 @@ struct MadDecoder { | ||||
| 	bool found_first_frame = false; | ||||
| 	bool decoded_first_frame = false; | ||||
| 	unsigned long bit_rate; | ||||
| 	Decoder *const decoder; | ||||
| 	DecoderClient *const client; | ||||
| 	InputStream &input_stream; | ||||
| 	enum mad_layer layer = mad_layer(0); | ||||
|  | ||||
| 	MadDecoder(Decoder *decoder, InputStream &input_stream); | ||||
| 	MadDecoder(DecoderClient *client, InputStream &input_stream); | ||||
| 	~MadDecoder(); | ||||
|  | ||||
| 	bool Seek(long offset); | ||||
| @@ -195,9 +195,9 @@ struct MadDecoder { | ||||
| 	bool Read(); | ||||
| }; | ||||
|  | ||||
| MadDecoder::MadDecoder(Decoder *_decoder, | ||||
| MadDecoder::MadDecoder(DecoderClient *_client, | ||||
| 		       InputStream &_input_stream) | ||||
| 	:decoder(_decoder), input_stream(_input_stream) | ||||
| 	:client(_client), input_stream(_input_stream) | ||||
| { | ||||
| 	mad_stream_init(&stream); | ||||
| 	mad_stream_options(&stream, MAD_OPTION_IGNORECRC); | ||||
| @@ -243,7 +243,7 @@ MadDecoder::FillBuffer() | ||||
| 	if (length == 0) | ||||
| 		return false; | ||||
|  | ||||
| 	length = decoder_read(decoder, input_stream, dest, length); | ||||
| 	length = decoder_read(client, input_stream, dest, length); | ||||
| 	if (length == 0) | ||||
| 		return false; | ||||
|  | ||||
| @@ -333,7 +333,7 @@ MadDecoder::ParseId3(size_t tagsize, Tag **mpd_tag) | ||||
| 		memcpy(allocated, stream.this_frame, count); | ||||
| 		mad_stream_skip(&(stream), count); | ||||
|  | ||||
| 		if (!decoder_read_full(decoder, input_stream, | ||||
| 		if (!decoder_read_full(client, input_stream, | ||||
| 				       allocated + count, tagsize - count)) { | ||||
| 			LogDebug(mad_domain, "error parsing ID3 tag"); | ||||
| 			delete[] allocated; | ||||
| @@ -357,15 +357,15 @@ MadDecoder::ParseId3(size_t tagsize, Tag **mpd_tag) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (decoder != nullptr) { | ||||
| 	if (client != nullptr) { | ||||
| 		ReplayGainInfo rgi; | ||||
|  | ||||
| 		if (parse_id3_replay_gain_info(rgi, id3_tag)) { | ||||
| 			decoder_replay_gain(*decoder, &rgi); | ||||
| 			decoder_replay_gain(*client, &rgi); | ||||
| 			found_replay_gain = true; | ||||
| 		} | ||||
|  | ||||
| 		decoder_mixramp(*decoder, parse_id3_mixramp(id3_tag)); | ||||
| 		decoder_mixramp(*client, parse_id3_mixramp(id3_tag)); | ||||
| 	} | ||||
|  | ||||
| 	id3_tag_delete(id3_tag); | ||||
| @@ -383,7 +383,7 @@ MadDecoder::ParseId3(size_t tagsize, Tag **mpd_tag) | ||||
| 		mad_stream_skip(&stream, tagsize); | ||||
| 	} else { | ||||
| 		mad_stream_skip(&stream, count); | ||||
| 		decoder_skip(decoder, input_stream, tagsize - count); | ||||
| 		decoder_skip(client, input_stream, tagsize - count); | ||||
| 	} | ||||
| #endif | ||||
| } | ||||
| @@ -800,13 +800,13 @@ MadDecoder::DecodeFirstFrame(Tag **tag) | ||||
|  | ||||
| 			/* Album gain isn't currently used.  See comment in | ||||
| 			 * parse_lame() for details. -- jat */ | ||||
| 			if (decoder != nullptr && !found_replay_gain && | ||||
| 			if (client != nullptr && !found_replay_gain && | ||||
| 			    lame.track_gain) { | ||||
| 				ReplayGainInfo rgi; | ||||
| 				rgi.Clear(); | ||||
| 				rgi.tuples[REPLAY_GAIN_TRACK].gain = lame.track_gain; | ||||
| 				rgi.tuples[REPLAY_GAIN_TRACK].peak = lame.peak; | ||||
| 				decoder_replay_gain(*decoder, &rgi); | ||||
| 				decoder_replay_gain(*client, &rgi); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -903,7 +903,7 @@ MadDecoder::SendPCM(unsigned i, unsigned pcm_length) | ||||
| 				       MAD_NCHANNELS(&frame.header)); | ||||
| 		num_samples *= MAD_NCHANNELS(&frame.header); | ||||
|  | ||||
| 		auto cmd = decoder_data(*decoder, input_stream, output_buffer, | ||||
| 		auto cmd = decoder_data(*client, input_stream, output_buffer, | ||||
| 					sizeof(output_buffer[0]) * num_samples, | ||||
| 					bit_rate / 1000); | ||||
| 		if (cmd != DecoderCommand::NONE) | ||||
| @@ -986,17 +986,17 @@ MadDecoder::Read() | ||||
| 			assert(input_stream.IsSeekable()); | ||||
|  | ||||
| 			unsigned long j = | ||||
| 				TimeToFrame(decoder_seek_time(*decoder)); | ||||
| 				TimeToFrame(decoder_seek_time(*client)); | ||||
| 			if (j < highest_frame) { | ||||
| 				if (Seek(frame_offsets[j])) { | ||||
| 					current_frame = j; | ||||
| 					decoder_command_finished(*decoder); | ||||
| 					decoder_command_finished(*client); | ||||
| 				} else | ||||
| 					decoder_seek_error(*decoder); | ||||
| 					decoder_seek_error(*client); | ||||
| 			} else { | ||||
| 				seek_time = decoder_seek_time(*decoder); | ||||
| 				seek_time = decoder_seek_time(*client); | ||||
| 				mute_frame = MUTEFRAME_SEEK; | ||||
| 				decoder_command_finished(*decoder); | ||||
| 				decoder_command_finished(*client); | ||||
| 			} | ||||
| 		} else if (cmd != DecoderCommand::NONE) | ||||
| 			return false; | ||||
| @@ -1010,7 +1010,7 @@ MadDecoder::Read() | ||||
| 			ret = DecodeNextFrameHeader(&tag); | ||||
|  | ||||
| 			if (tag != nullptr) { | ||||
| 				decoder_tag(*decoder, input_stream, | ||||
| 				decoder_tag(*client, input_stream, | ||||
| 					    std::move(*tag)); | ||||
| 				delete tag; | ||||
| 			} | ||||
| @@ -1034,15 +1034,15 @@ MadDecoder::Read() | ||||
| } | ||||
|  | ||||
| static void | ||||
| mp3_decode(Decoder &decoder, InputStream &input_stream) | ||||
| mp3_decode(DecoderClient &client, InputStream &input_stream) | ||||
| { | ||||
| 	MadDecoder data(&decoder, input_stream); | ||||
| 	MadDecoder data(&client, input_stream); | ||||
|  | ||||
| 	Tag *tag = nullptr; | ||||
| 	if (!data.DecodeFirstFrame(&tag)) { | ||||
| 		delete tag; | ||||
|  | ||||
| 		if (decoder_get_command(decoder) == DecoderCommand::NONE) | ||||
| 		if (decoder_get_command(client) == DecoderCommand::NONE) | ||||
| 			LogError(mad_domain, | ||||
| 				 "input/Input does not appear to be a mp3 bit stream"); | ||||
| 		return; | ||||
| @@ -1050,7 +1050,7 @@ mp3_decode(Decoder &decoder, InputStream &input_stream) | ||||
|  | ||||
| 	data.AllocateBuffers(); | ||||
|  | ||||
| 	decoder_initialized(decoder, | ||||
| 	decoder_initialized(client, | ||||
| 			    CheckAudioFormat(data.frame.header.samplerate, | ||||
| 					     SampleFormat::S24_P32, | ||||
| 					     MAD_NCHANNELS(&data.frame.header)), | ||||
| @@ -1058,7 +1058,7 @@ mp3_decode(Decoder &decoder, InputStream &input_stream) | ||||
| 			    data.total_time); | ||||
|  | ||||
| 	if (tag != nullptr) { | ||||
| 		decoder_tag(decoder, input_stream, std::move(*tag)); | ||||
| 		decoder_tag(client, input_stream, std::move(*tag)); | ||||
| 		delete tag; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -147,7 +147,7 @@ mikmod_decoder_finish(void) | ||||
| } | ||||
|  | ||||
| static void | ||||
| mikmod_decoder_file_decode(Decoder &decoder, Path path_fs) | ||||
| mikmod_decoder_file_decode(DecoderClient &client, Path path_fs) | ||||
| { | ||||
| 	/* deconstify the path because libmikmod wants a non-const | ||||
| 	   string pointer */ | ||||
| @@ -170,7 +170,7 @@ mikmod_decoder_file_decode(Decoder &decoder, Path path_fs) | ||||
| 	const AudioFormat audio_format(mikmod_sample_rate, SampleFormat::S16, 2); | ||||
| 	assert(audio_format.IsValid()); | ||||
|  | ||||
| 	decoder_initialized(decoder, audio_format, false, | ||||
| 	decoder_initialized(client, audio_format, false, | ||||
| 			    SignedSongTime::Negative()); | ||||
|  | ||||
| 	Player_Start(handle); | ||||
| @@ -178,7 +178,7 @@ mikmod_decoder_file_decode(Decoder &decoder, Path path_fs) | ||||
| 	DecoderCommand cmd = DecoderCommand::NONE; | ||||
| 	while (cmd == DecoderCommand::NONE && Player_Active()) { | ||||
| 		ret = VC_WriteBytes(buffer, sizeof(buffer)); | ||||
| 		cmd = decoder_data(decoder, nullptr, buffer, ret, 0); | ||||
| 		cmd = decoder_data(client, nullptr, buffer, ret, 0); | ||||
| 	} | ||||
|  | ||||
| 	Player_Stop(); | ||||
|   | ||||
| @@ -52,7 +52,7 @@ modplug_decoder_init(const ConfigBlock &block) | ||||
| } | ||||
|  | ||||
| static WritableBuffer<uint8_t> | ||||
| mod_loadfile(Decoder *decoder, InputStream &is) | ||||
| mod_loadfile(DecoderClient *client, InputStream &is) | ||||
| { | ||||
| 	//known/unknown size, preallocate array, lets read in chunks | ||||
|  | ||||
| @@ -83,7 +83,7 @@ mod_loadfile(Decoder *decoder, InputStream &is) | ||||
| 	uint8_t *p = buffer.begin(); | ||||
|  | ||||
| 	while (true) { | ||||
| 		size_t ret = decoder_read(decoder, is, p, end - p); | ||||
| 		size_t ret = decoder_read(client, is, p, end - p); | ||||
| 		if (ret == 0) { | ||||
| 			if (is.LockIsEOF()) | ||||
| 				/* end of file */ | ||||
| @@ -112,9 +112,9 @@ mod_loadfile(Decoder *decoder, InputStream &is) | ||||
| } | ||||
|  | ||||
| static ModPlugFile * | ||||
| LoadModPlugFile(Decoder *decoder, InputStream &is) | ||||
| LoadModPlugFile(DecoderClient *client, InputStream &is) | ||||
| { | ||||
| 	const auto buffer = mod_loadfile(decoder, is); | ||||
| 	const auto buffer = mod_loadfile(client, is); | ||||
| 	if (buffer.IsNull()) { | ||||
| 		LogWarning(modplug_domain, "could not load stream"); | ||||
| 		return nullptr; | ||||
| @@ -126,7 +126,7 @@ LoadModPlugFile(Decoder *decoder, InputStream &is) | ||||
| } | ||||
|  | ||||
| static void | ||||
| mod_decode(Decoder &decoder, InputStream &is) | ||||
| mod_decode(DecoderClient &client, InputStream &is) | ||||
| { | ||||
| 	ModPlug_Settings settings; | ||||
| 	int ret; | ||||
| @@ -142,7 +142,7 @@ mod_decode(Decoder &decoder, InputStream &is) | ||||
| 	/* insert more setting changes here */ | ||||
| 	ModPlug_SetSettings(&settings); | ||||
|  | ||||
| 	ModPlugFile *f = LoadModPlugFile(&decoder, is); | ||||
| 	ModPlugFile *f = LoadModPlugFile(&client, is); | ||||
| 	if (f == nullptr) { | ||||
| 		LogWarning(modplug_domain, "could not decode stream"); | ||||
| 		return; | ||||
| @@ -151,7 +151,7 @@ mod_decode(Decoder &decoder, InputStream &is) | ||||
| 	static constexpr AudioFormat audio_format(44100, SampleFormat::S16, 2); | ||||
| 	assert(audio_format.IsValid()); | ||||
|  | ||||
| 	decoder_initialized(decoder, audio_format, | ||||
| 	decoder_initialized(client, audio_format, | ||||
| 			    is.IsSeekable(), | ||||
| 			    SongTime::FromMS(ModPlug_GetLength(f))); | ||||
|  | ||||
| @@ -161,13 +161,13 @@ mod_decode(Decoder &decoder, InputStream &is) | ||||
| 		if (ret <= 0) | ||||
| 			break; | ||||
|  | ||||
| 		cmd = decoder_data(decoder, nullptr, | ||||
| 		cmd = decoder_data(client, nullptr, | ||||
| 				   audio_buffer, ret, | ||||
| 				   0); | ||||
|  | ||||
| 		if (cmd == DecoderCommand::SEEK) { | ||||
| 			ModPlug_Seek(f, decoder_seek_time(decoder).ToMS()); | ||||
| 			decoder_command_finished(decoder); | ||||
| 			ModPlug_Seek(f, decoder_seek_time(client).ToMS()); | ||||
| 			decoder_command_finished(client); | ||||
| 		} | ||||
|  | ||||
| 	} while (cmd != DecoderCommand::STOP); | ||||
|   | ||||
| @@ -37,10 +37,10 @@ | ||||
|  | ||||
| struct mpc_decoder_data { | ||||
| 	InputStream &is; | ||||
| 	Decoder *decoder; | ||||
| 	DecoderClient *client; | ||||
|  | ||||
| 	mpc_decoder_data(InputStream &_is, Decoder *_decoder) | ||||
| 		:is(_is), decoder(_decoder) {} | ||||
| 	mpc_decoder_data(InputStream &_is, DecoderClient *_client) | ||||
| 		:is(_is), client(_client) {} | ||||
| }; | ||||
|  | ||||
| static constexpr Domain mpcdec_domain("mpcdec"); | ||||
| @@ -54,7 +54,7 @@ mpc_read_cb(mpc_reader *reader, void *ptr, mpc_int32_t size) | ||||
| 	struct mpc_decoder_data *data = | ||||
| 		(struct mpc_decoder_data *)reader->data; | ||||
|  | ||||
| 	return decoder_read(data->decoder, data->is, ptr, size); | ||||
| 	return decoder_read(data->client, data->is, ptr, size); | ||||
| } | ||||
|  | ||||
| static mpc_bool_t | ||||
| @@ -138,9 +138,9 @@ mpc_to_mpd_buffer(MpcdecSampleTraits::pointer_type dest, | ||||
| } | ||||
|  | ||||
| static void | ||||
| mpcdec_decode(Decoder &mpd_decoder, InputStream &is) | ||||
| mpcdec_decode(DecoderClient &client, InputStream &is) | ||||
| { | ||||
| 	mpc_decoder_data data(is, &mpd_decoder); | ||||
| 	mpc_decoder_data data(is, &client); | ||||
|  | ||||
| 	mpc_reader reader; | ||||
| 	reader.read = mpc_read_cb; | ||||
| @@ -152,7 +152,7 @@ mpcdec_decode(Decoder &mpd_decoder, InputStream &is) | ||||
|  | ||||
| 	mpc_demux *demux = mpc_demux_init(&reader); | ||||
| 	if (demux == nullptr) { | ||||
| 		if (decoder_get_command(mpd_decoder) != DecoderCommand::STOP) | ||||
| 		if (decoder_get_command(client) != DecoderCommand::STOP) | ||||
| 			LogWarning(mpcdec_domain, | ||||
| 				   "Not a valid musepack stream"); | ||||
| 		return; | ||||
| @@ -172,9 +172,9 @@ mpcdec_decode(Decoder &mpd_decoder, InputStream &is) | ||||
| 	rgi.tuples[REPLAY_GAIN_TRACK].gain = MPC_OLD_GAIN_REF  - (info.gain_title  / 256.); | ||||
| 	rgi.tuples[REPLAY_GAIN_TRACK].peak = pow(10, info.peak_title / 256. / 20) / 32767; | ||||
|  | ||||
| 	decoder_replay_gain(mpd_decoder, &rgi); | ||||
| 	decoder_replay_gain(client, &rgi); | ||||
|  | ||||
| 	decoder_initialized(mpd_decoder, audio_format, | ||||
| 	decoder_initialized(client, audio_format, | ||||
| 			    is.IsSeekable(), | ||||
| 			    SongTime::FromS(mpc_streaminfo_get_length(&info))); | ||||
|  | ||||
| @@ -182,15 +182,15 @@ mpcdec_decode(Decoder &mpd_decoder, InputStream &is) | ||||
| 	do { | ||||
| 		if (cmd == DecoderCommand::SEEK) { | ||||
| 			mpc_int64_t where = | ||||
| 				decoder_seek_where_frame(mpd_decoder); | ||||
| 				decoder_seek_where_frame(client); | ||||
| 			bool success; | ||||
|  | ||||
| 			success = mpc_demux_seek_sample(demux, where) | ||||
| 				== MPC_STATUS_OK; | ||||
| 			if (success) | ||||
| 				decoder_command_finished(mpd_decoder); | ||||
| 				decoder_command_finished(client); | ||||
| 			else | ||||
| 				decoder_seek_error(mpd_decoder); | ||||
| 				decoder_seek_error(client); | ||||
| 		} | ||||
|  | ||||
| 		MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH]; | ||||
| @@ -215,7 +215,7 @@ mpcdec_decode(Decoder &mpd_decoder, InputStream &is) | ||||
| 		long bit_rate = unsigned(frame.bits) * audio_format.sample_rate | ||||
| 			/ (1000 * frame.samples); | ||||
|  | ||||
| 		cmd = decoder_data(mpd_decoder, is, | ||||
| 		cmd = decoder_data(client, is, | ||||
| 				   chunk, ret * sizeof(chunk[0]), | ||||
| 				   bit_rate); | ||||
| 	} while (cmd != DecoderCommand::STOP); | ||||
|   | ||||
| @@ -116,7 +116,7 @@ AddTagItem(TagBuilder &tag, TagType type, const mpg123_string *s) | ||||
| } | ||||
|  | ||||
| static void | ||||
| mpd_mpg123_id3v2_tag(Decoder &decoder, const mpg123_id3v2 &id3v2) | ||||
| mpd_mpg123_id3v2_tag(DecoderClient &client, const mpg123_id3v2 &id3v2) | ||||
| { | ||||
| 	TagBuilder tag; | ||||
|  | ||||
| @@ -129,11 +129,11 @@ mpd_mpg123_id3v2_tag(Decoder &decoder, const mpg123_id3v2 &id3v2) | ||||
| 	for (size_t i = 0, n = id3v2.comments; i < n; ++i) | ||||
| 		AddTagItem(tag, TAG_COMMENT, id3v2.comment_list[i].text); | ||||
|  | ||||
| 	decoder_tag(decoder, nullptr, tag.Commit()); | ||||
| 	decoder_tag(client, nullptr, tag.Commit()); | ||||
| } | ||||
|  | ||||
| static void | ||||
| mpd_mpg123_id3v2_extras(Decoder &decoder, const mpg123_id3v2 &id3v2) | ||||
| mpd_mpg123_id3v2_extras(DecoderClient &client, const mpg123_id3v2 &id3v2) | ||||
| { | ||||
| 	ReplayGainInfo replay_gain; | ||||
| 	replay_gain.Clear(); | ||||
| @@ -154,21 +154,21 @@ mpd_mpg123_id3v2_extras(Decoder &decoder, const mpg123_id3v2 &id3v2) | ||||
| 	} | ||||
|  | ||||
| 	if (found_replay_gain) | ||||
| 		decoder_replay_gain(decoder, &replay_gain); | ||||
| 		decoder_replay_gain(client, &replay_gain); | ||||
|  | ||||
| 	if (found_mixramp) | ||||
| 		decoder_mixramp(decoder, std::move(mix_ramp)); | ||||
| 		decoder_mixramp(client, std::move(mix_ramp)); | ||||
| } | ||||
|  | ||||
| static void | ||||
| mpd_mpg123_id3v2(Decoder &decoder, const mpg123_id3v2 &id3v2) | ||||
| mpd_mpg123_id3v2(DecoderClient &client, const mpg123_id3v2 &id3v2) | ||||
| { | ||||
| 	mpd_mpg123_id3v2_tag(decoder, id3v2); | ||||
| 	mpd_mpg123_id3v2_extras(decoder, id3v2); | ||||
| 	mpd_mpg123_id3v2_tag(client, id3v2); | ||||
| 	mpd_mpg123_id3v2_extras(client, id3v2); | ||||
| } | ||||
|  | ||||
| static void | ||||
| mpd_mpg123_meta(Decoder &decoder, mpg123_handle *const handle) | ||||
| mpd_mpg123_meta(DecoderClient &client, mpg123_handle *const handle) | ||||
| { | ||||
| 	if ((mpg123_meta_check(handle) & MPG123_NEW_ID3) == 0) | ||||
| 		return; | ||||
| @@ -179,11 +179,11 @@ mpd_mpg123_meta(Decoder &decoder, mpg123_handle *const handle) | ||||
| 		return; | ||||
|  | ||||
| 	if (v2 != nullptr) | ||||
| 		mpd_mpg123_id3v2(decoder, *v2); | ||||
| 		mpd_mpg123_id3v2(client, *v2); | ||||
| } | ||||
|  | ||||
| static void | ||||
| mpd_mpg123_file_decode(Decoder &decoder, Path path_fs) | ||||
| mpd_mpg123_file_decode(DecoderClient &client, Path path_fs) | ||||
| { | ||||
| 	/* open the file */ | ||||
|  | ||||
| @@ -210,7 +210,7 @@ mpd_mpg123_file_decode(Decoder &decoder, Path path_fs) | ||||
| 		SongTime::FromScale<uint64_t>(num_samples, | ||||
| 					      audio_format.sample_rate); | ||||
|  | ||||
| 	decoder_initialized(decoder, audio_format, true, duration); | ||||
| 	decoder_initialized(client, audio_format, true, duration); | ||||
|  | ||||
| 	struct mpg123_frameinfo info; | ||||
| 	if (mpg123_info(handle, &info) != MPG123_OK) { | ||||
| @@ -232,7 +232,7 @@ mpd_mpg123_file_decode(Decoder &decoder, Path path_fs) | ||||
| 	DecoderCommand cmd; | ||||
| 	do { | ||||
| 		/* read metadata */ | ||||
| 		mpd_mpg123_meta(decoder, handle); | ||||
| 		mpd_mpg123_meta(client, handle); | ||||
|  | ||||
| 		/* decode */ | ||||
|  | ||||
| @@ -257,16 +257,16 @@ mpd_mpg123_file_decode(Decoder &decoder, Path path_fs) | ||||
|  | ||||
| 		/* send to MPD */ | ||||
|  | ||||
| 		cmd = decoder_data(decoder, nullptr, buffer, nbytes, info.bitrate); | ||||
| 		cmd = decoder_data(client, nullptr, buffer, nbytes, info.bitrate); | ||||
|  | ||||
| 		if (cmd == DecoderCommand::SEEK) { | ||||
| 			off_t c = decoder_seek_where_frame(decoder); | ||||
| 			off_t c = decoder_seek_where_frame(client); | ||||
| 			c = mpg123_seek(handle, c, SEEK_SET); | ||||
| 			if (c < 0) | ||||
| 				decoder_seek_error(decoder); | ||||
| 				decoder_seek_error(client); | ||||
| 			else { | ||||
| 				decoder_command_finished(decoder); | ||||
| 				decoder_timestamp(decoder, c/(double)audio_format.sample_rate); | ||||
| 				decoder_command_finished(client); | ||||
| 				decoder_timestamp(client, c/(double)audio_format.sample_rate); | ||||
| 			} | ||||
|  | ||||
| 			cmd = DecoderCommand::NONE; | ||||
|   | ||||
| @@ -28,13 +28,13 @@ | ||||
| #include <string.h> | ||||
|  | ||||
| enum ogg_codec | ||||
| ogg_codec_detect(Decoder *decoder, InputStream &is) | ||||
| ogg_codec_detect(DecoderClient *client, InputStream &is) | ||||
| { | ||||
| 	/* oggflac detection based on code in ogg123 and this post | ||||
| 	 * http://lists.xiph.org/pipermail/flac/2004-December/000393.html | ||||
| 	 * ogg123 trunk still doesn't have this patch as of June 2005 */ | ||||
| 	unsigned char buf[41]; | ||||
| 	size_t r = decoder_read(decoder, is, buf, sizeof(buf)); | ||||
| 	size_t r = decoder_read(client, is, buf, sizeof(buf)); | ||||
| 	if (r < sizeof(buf) || memcmp(buf, "OggS", 4) != 0) | ||||
| 		return OGG_CODEC_UNKNOWN; | ||||
|  | ||||
|   | ||||
| @@ -24,7 +24,7 @@ | ||||
| #ifndef MPD_OGG_CODEC_HXX | ||||
| #define MPD_OGG_CODEC_HXX | ||||
|  | ||||
| struct Decoder; | ||||
| class DecoderClient; | ||||
| class InputStream; | ||||
|  | ||||
| enum ogg_codec { | ||||
| @@ -35,6 +35,6 @@ enum ogg_codec { | ||||
| }; | ||||
|  | ||||
| enum ogg_codec | ||||
| ogg_codec_detect(Decoder *decoder, InputStream &is); | ||||
| ogg_codec_detect(DecoderClient *client, InputStream &is); | ||||
|  | ||||
| #endif /* _OGG_COMMON_H */ | ||||
|   | ||||
| @@ -45,7 +45,7 @@ OggDecoder::LoadEndPacket(ogg_packet &packet) const | ||||
| 	bool result; | ||||
|  | ||||
| 	{ | ||||
| 		DecoderReader reader(decoder, input_stream); | ||||
| 		DecoderReader reader(client, input_stream); | ||||
| 		OggSyncState sync2(reader); | ||||
| 		OggStreamState stream2(GetSerialNo()); | ||||
| 		result = OggSeekFindEOS(sync2, stream2, packet, | ||||
|   | ||||
| @@ -28,13 +28,13 @@ class OggDecoder : public OggVisitor { | ||||
| 	ogg_int64_t end_granulepos; | ||||
|  | ||||
| protected: | ||||
| 	Decoder &decoder; | ||||
| 	DecoderClient &client; | ||||
| 	InputStream &input_stream; | ||||
|  | ||||
| public: | ||||
| 	explicit OggDecoder(DecoderReader &reader) | ||||
| 		:OggVisitor(reader), | ||||
| 		 decoder(reader.GetDecoder()), | ||||
| 		 client(reader.GetClient()), | ||||
| 		 input_stream(reader.GetInputStream()) {} | ||||
|  | ||||
| 	bool Seek(OggSyncState &oy, uint64_t where_frame); | ||||
|   | ||||
| @@ -175,14 +175,14 @@ MPDOpusDecoder::OnOggBeginning(const ogg_packet &packet) | ||||
| 	previous_channels = channels; | ||||
| 	const AudioFormat audio_format(opus_sample_rate, | ||||
| 				       SampleFormat::S16, channels); | ||||
| 	decoder_initialized(decoder, audio_format, | ||||
| 	decoder_initialized(client, audio_format, | ||||
| 			    eos_granulepos > 0, duration); | ||||
| 	frame_size = audio_format.GetFrameSize(); | ||||
|  | ||||
| 	output_buffer = new opus_int16[opus_output_buffer_frames | ||||
| 				       * audio_format.channels]; | ||||
|  | ||||
| 	auto cmd = decoder_get_command(decoder); | ||||
| 	auto cmd = decoder_get_command(client); | ||||
| 	if (cmd != DecoderCommand::NONE) | ||||
| 		throw cmd; | ||||
| } | ||||
| @@ -213,10 +213,10 @@ MPDOpusDecoder::HandleTags(const ogg_packet &packet) | ||||
| 			 &rgi, | ||||
| 			 add_tag_handler, &tag_builder) && | ||||
| 	    !tag_builder.IsEmpty()) { | ||||
| 		decoder_replay_gain(decoder, &rgi); | ||||
| 		decoder_replay_gain(client, &rgi); | ||||
|  | ||||
| 		Tag tag = tag_builder.Commit(); | ||||
| 		auto cmd = decoder_tag(decoder, input_stream, std::move(tag)); | ||||
| 		auto cmd = decoder_tag(client, input_stream, std::move(tag)); | ||||
| 		if (cmd != DecoderCommand::NONE) | ||||
| 			throw cmd; | ||||
| 	} | ||||
| @@ -238,14 +238,14 @@ MPDOpusDecoder::HandleAudio(const ogg_packet &packet) | ||||
|  | ||||
| 	if (nframes > 0) { | ||||
| 		const size_t nbytes = nframes * frame_size; | ||||
| 		auto cmd = decoder_data(decoder, input_stream, | ||||
| 		auto cmd = decoder_data(client, input_stream, | ||||
| 					output_buffer, nbytes, | ||||
| 					0); | ||||
| 		if (cmd != DecoderCommand::NONE) | ||||
| 			throw cmd; | ||||
|  | ||||
| 		if (packet.granulepos > 0) | ||||
| 			decoder_timestamp(decoder, | ||||
| 			decoder_timestamp(client, | ||||
| 					  double(packet.granulepos) | ||||
| 					  / opus_sample_rate); | ||||
| 	} | ||||
| @@ -269,10 +269,10 @@ MPDOpusDecoder::Seek(uint64_t where_frame) | ||||
| } | ||||
|  | ||||
| static void | ||||
| mpd_opus_stream_decode(Decoder &decoder, | ||||
| mpd_opus_stream_decode(DecoderClient &client, | ||||
| 		       InputStream &input_stream) | ||||
| { | ||||
| 	if (ogg_codec_detect(&decoder, input_stream) != OGG_CODEC_OPUS) | ||||
| 	if (ogg_codec_detect(&client, input_stream) != OGG_CODEC_OPUS) | ||||
| 		return; | ||||
|  | ||||
| 	/* rewind the stream, because ogg_codec_detect() has | ||||
| @@ -282,7 +282,7 @@ mpd_opus_stream_decode(Decoder &decoder, | ||||
| 	} catch (const std::runtime_error &) { | ||||
| 	} | ||||
|  | ||||
| 	DecoderReader reader(decoder, input_stream); | ||||
| 	DecoderReader reader(client, input_stream); | ||||
|  | ||||
| 	MPDOpusDecoder d(reader); | ||||
|  | ||||
| @@ -292,10 +292,10 @@ mpd_opus_stream_decode(Decoder &decoder, | ||||
| 			break; | ||||
| 		} catch (DecoderCommand cmd) { | ||||
| 			if (cmd == DecoderCommand::SEEK) { | ||||
| 				if (d.Seek(decoder_seek_where_frame(decoder))) | ||||
| 					decoder_command_finished(decoder); | ||||
| 				if (d.Seek(decoder_seek_where_frame(client))) | ||||
| 					decoder_command_finished(client); | ||||
| 				else | ||||
| 					decoder_seek_error(decoder); | ||||
| 					decoder_seek_error(client); | ||||
| 			} else if (cmd != DecoderCommand::NONE) | ||||
| 				break; | ||||
| 		} | ||||
|   | ||||
| @@ -39,13 +39,13 @@ static constexpr Domain pcm_decoder_domain("pcm_decoder"); | ||||
|  | ||||
| template<typename B> | ||||
| static bool | ||||
| FillBuffer(Decoder &decoder, InputStream &is, B &buffer) | ||||
| FillBuffer(DecoderClient &client, InputStream &is, B &buffer) | ||||
| { | ||||
| 	buffer.Shift(); | ||||
| 	auto w = buffer.Write(); | ||||
| 	assert(!w.IsEmpty()); | ||||
|  | ||||
| 	size_t nbytes = decoder_read(decoder, is, w.data, w.size); | ||||
| 	size_t nbytes = decoder_read(client, is, w.data, w.size); | ||||
| 	if (nbytes == 0 && is.LockIsEOF()) | ||||
| 		return false; | ||||
|  | ||||
| @@ -54,7 +54,7 @@ FillBuffer(Decoder &decoder, InputStream &is, B &buffer) | ||||
| } | ||||
|  | ||||
| static void | ||||
| pcm_stream_decode(Decoder &decoder, InputStream &is) | ||||
| pcm_stream_decode(DecoderClient &client, InputStream &is) | ||||
| { | ||||
| 	AudioFormat audio_format = { | ||||
| 		44100, | ||||
| @@ -143,14 +143,14 @@ pcm_stream_decode(Decoder &decoder, InputStream &is) | ||||
| 						      audio_format.sample_rate) | ||||
| 		: SignedSongTime::Negative(); | ||||
|  | ||||
| 	decoder_initialized(decoder, audio_format, | ||||
| 	decoder_initialized(client, audio_format, | ||||
| 			    is.IsSeekable(), total_time); | ||||
|  | ||||
| 	StaticFifoBuffer<uint8_t, 4096> buffer; | ||||
|  | ||||
| 	DecoderCommand cmd; | ||||
| 	do { | ||||
| 		if (!FillBuffer(decoder, is, buffer)) | ||||
| 		if (!FillBuffer(client, is, buffer)) | ||||
| 			break; | ||||
|  | ||||
| 		auto r = buffer.Read(); | ||||
| @@ -166,19 +166,19 @@ pcm_stream_decode(Decoder &decoder, InputStream &is) | ||||
| 					 (uint16_t *)(r.data + r.size)); | ||||
|  | ||||
| 		cmd = !r.IsEmpty() | ||||
| 			? decoder_data(decoder, is, r.data, r.size, 0) | ||||
| 			: decoder_get_command(decoder); | ||||
| 			? decoder_data(client, is, r.data, r.size, 0) | ||||
| 			: decoder_get_command(client); | ||||
| 		if (cmd == DecoderCommand::SEEK) { | ||||
| 			uint64_t frame = decoder_seek_where_frame(decoder); | ||||
| 			uint64_t frame = decoder_seek_where_frame(client); | ||||
| 			offset_type offset = frame * frame_size; | ||||
|  | ||||
| 			try { | ||||
| 				is.LockSeek(offset); | ||||
| 				buffer.Clear(); | ||||
| 				decoder_command_finished(decoder); | ||||
| 				decoder_command_finished(client); | ||||
| 			} catch (const std::runtime_error &e) { | ||||
| 				LogError(e); | ||||
| 				decoder_seek_error(decoder); | ||||
| 				decoder_seek_error(client); | ||||
| 			} | ||||
|  | ||||
| 			cmd = DecoderCommand::NONE; | ||||
|   | ||||
| @@ -179,7 +179,7 @@ get_song_length(SidTuneMod &tune) | ||||
| #endif | ||||
|  | ||||
| static void | ||||
| sidplay_file_decode(Decoder &decoder, Path path_fs) | ||||
| sidplay_file_decode(DecoderClient &client, Path path_fs) | ||||
| { | ||||
| 	int channels; | ||||
|  | ||||
| @@ -337,7 +337,7 @@ sidplay_file_decode(Decoder &decoder, Path path_fs) | ||||
| 	const AudioFormat audio_format(48000, SampleFormat::S16, channels); | ||||
| 	assert(audio_format.IsValid()); | ||||
|  | ||||
| 	decoder_initialized(decoder, audio_format, true, duration); | ||||
| 	decoder_initialized(client, audio_format, true, duration); | ||||
|  | ||||
| 	/* .. and play */ | ||||
|  | ||||
| @@ -366,14 +366,14 @@ sidplay_file_decode(Decoder &decoder, Path path_fs) | ||||
| 		const size_t nbytes = result; | ||||
| #endif | ||||
|  | ||||
| 		decoder_timestamp(decoder, (double)player.time() / timebase); | ||||
| 		decoder_timestamp(client, (double)player.time() / timebase); | ||||
|  | ||||
| 		cmd = decoder_data(decoder, nullptr, buffer, nbytes, 0); | ||||
| 		cmd = decoder_data(client, nullptr, buffer, nbytes, 0); | ||||
|  | ||||
| 		if (cmd == DecoderCommand::SEEK) { | ||||
| 			unsigned data_time = player.time(); | ||||
| 			unsigned target_time = | ||||
| 				decoder_seek_time(decoder).ToScale(timebase); | ||||
| 				decoder_seek_time(client).ToScale(timebase); | ||||
|  | ||||
| 			/* can't rewind so return to zero and seek forward */ | ||||
| 			if(target_time<data_time) { | ||||
| @@ -386,7 +386,7 @@ sidplay_file_decode(Decoder &decoder, Path path_fs) | ||||
| 			       player.play(buffer, ARRAY_SIZE(buffer)) > 0) | ||||
| 				data_time = player.time(); | ||||
|  | ||||
| 			decoder_command_finished(decoder); | ||||
| 			decoder_command_finished(client); | ||||
| 		} | ||||
|  | ||||
| 		if (end > 0 && player.time() >= end) | ||||
|   | ||||
| @@ -40,13 +40,13 @@ sndfile_init(gcc_unused const ConfigBlock &block) | ||||
| } | ||||
|  | ||||
| struct SndfileInputStream { | ||||
| 	Decoder *const decoder; | ||||
| 	DecoderClient *const client; | ||||
| 	InputStream &is; | ||||
|  | ||||
| 	size_t Read(void *buffer, size_t size) { | ||||
| 		/* libsndfile chokes on partial reads; therefore | ||||
| 		   always force full reads */ | ||||
| 		return decoder_read_full(decoder, is, buffer, size) | ||||
| 		return decoder_read_full(client, is, buffer, size) | ||||
| 			? size | ||||
| 			: 0; | ||||
| 	} | ||||
| @@ -186,13 +186,13 @@ sndfile_read_frames(SNDFILE *sf, SampleFormat format, | ||||
| } | ||||
|  | ||||
| static void | ||||
| sndfile_stream_decode(Decoder &decoder, InputStream &is) | ||||
| sndfile_stream_decode(DecoderClient &client, InputStream &is) | ||||
| { | ||||
| 	SF_INFO info; | ||||
|  | ||||
| 	info.format = 0; | ||||
|  | ||||
| 	SndfileInputStream sis{&decoder, is}; | ||||
| 	SndfileInputStream sis{&client, is}; | ||||
| 	SNDFILE *const sf = sf_open_virtual(&vio, SFM_READ, &info, &sis); | ||||
| 	if (sf == nullptr) { | ||||
| 		FormatWarning(sndfile_domain, "sf_open_virtual() failed: %s", | ||||
| @@ -205,7 +205,7 @@ sndfile_stream_decode(Decoder &decoder, InputStream &is) | ||||
| 				 sndfile_sample_format(info), | ||||
| 				 info.channels); | ||||
|  | ||||
| 	decoder_initialized(decoder, audio_format, info.seekable, | ||||
| 	decoder_initialized(client, audio_format, info.seekable, | ||||
| 			    sndfile_duration(info)); | ||||
|  | ||||
| 	char buffer[16384]; | ||||
| @@ -222,16 +222,16 @@ sndfile_stream_decode(Decoder &decoder, InputStream &is) | ||||
| 		if (num_frames <= 0) | ||||
| 			break; | ||||
|  | ||||
| 		cmd = decoder_data(decoder, is, | ||||
| 		cmd = decoder_data(client, is, | ||||
| 				   buffer, num_frames * frame_size, | ||||
| 				   0); | ||||
| 		if (cmd == DecoderCommand::SEEK) { | ||||
| 			sf_count_t c = decoder_seek_where_frame(decoder); | ||||
| 			sf_count_t c = decoder_seek_where_frame(client); | ||||
| 			c = sf_seek(sf, c, SEEK_SET); | ||||
| 			if (c < 0) | ||||
| 				decoder_seek_error(decoder); | ||||
| 				decoder_seek_error(client); | ||||
| 			else | ||||
| 				decoder_command_finished(decoder); | ||||
| 				decoder_command_finished(client); | ||||
| 			cmd = DecoderCommand::NONE; | ||||
| 		} | ||||
| 	} while (cmd == DecoderCommand::NONE); | ||||
|   | ||||
| @@ -149,14 +149,14 @@ VorbisDecoder::OnOggBeginning(const ogg_packet &_packet) | ||||
| } | ||||
|  | ||||
| static void | ||||
| vorbis_send_comments(Decoder &decoder, InputStream &is, | ||||
| vorbis_send_comments(DecoderClient &client, InputStream &is, | ||||
| 		     char **comments) | ||||
| { | ||||
| 	Tag *tag = vorbis_comments_to_tag(comments); | ||||
| 	if (!tag) | ||||
| 		return; | ||||
|  | ||||
| 	decoder_tag(decoder, is, std::move(*tag)); | ||||
| 	decoder_tag(client, is, std::move(*tag)); | ||||
| 	delete tag; | ||||
| } | ||||
|  | ||||
| @@ -175,7 +175,7 @@ VorbisDecoder::SubmitInit() | ||||
| 						      audio_format.sample_rate) | ||||
| 		: SignedSongTime::Negative(); | ||||
|  | ||||
| 	decoder_initialized(decoder, audio_format, | ||||
| 	decoder_initialized(client, audio_format, | ||||
| 			    eos_granulepos > 0, duration); | ||||
| } | ||||
|  | ||||
| @@ -212,7 +212,7 @@ VorbisDecoder::SubmitSomePcm() | ||||
| 	vorbis_synthesis_read(&dsp, n_frames); | ||||
|  | ||||
| 	const size_t nbytes = n_frames * frame_size; | ||||
| 	auto cmd = decoder_data(decoder, input_stream, | ||||
| 	auto cmd = decoder_data(client, input_stream, | ||||
| 				buffer, nbytes, | ||||
| 				0); | ||||
| 	if (cmd != DecoderCommand::NONE) | ||||
| @@ -249,11 +249,11 @@ VorbisDecoder::OnOggPacket(const ogg_packet &_packet) | ||||
| 		} else | ||||
| 			SubmitInit(); | ||||
|  | ||||
| 		vorbis_send_comments(decoder, input_stream, vc.user_comments); | ||||
| 		vorbis_send_comments(client, input_stream, vc.user_comments); | ||||
|  | ||||
| 		ReplayGainInfo rgi; | ||||
| 		if (vorbis_comments_to_replay_gain(rgi, vc.user_comments)) | ||||
| 			decoder_replay_gain(decoder, &rgi); | ||||
| 			decoder_replay_gain(client, &rgi); | ||||
| 	} else { | ||||
| 		if (!dsp_initialized) { | ||||
| 			dsp_initialized = true; | ||||
| @@ -265,7 +265,7 @@ VorbisDecoder::OnOggPacket(const ogg_packet &_packet) | ||||
| 		if (vorbis_synthesis(&block, &packet) != 0) { | ||||
| 			/* ignore bad packets, but give the MPD core a | ||||
| 			   chance to stop us */ | ||||
| 			auto cmd = decoder_get_command(decoder); | ||||
| 			auto cmd = decoder_get_command(client); | ||||
| 			if (cmd != DecoderCommand::NONE) | ||||
| 				throw cmd; | ||||
| 			return; | ||||
| @@ -278,7 +278,7 @@ VorbisDecoder::OnOggPacket(const ogg_packet &_packet) | ||||
|  | ||||
| #ifndef HAVE_TREMOR | ||||
| 		if (packet.granulepos > 0) | ||||
| 			decoder_timestamp(decoder, | ||||
| 			decoder_timestamp(client, | ||||
| 					  vorbis_granule_time(&dsp, packet.granulepos)); | ||||
| #endif | ||||
| 	} | ||||
| @@ -301,10 +301,10 @@ vorbis_init(gcc_unused const ConfigBlock &block) | ||||
| } | ||||
|  | ||||
| static void | ||||
| vorbis_stream_decode(Decoder &decoder, | ||||
| vorbis_stream_decode(DecoderClient &client, | ||||
| 		     InputStream &input_stream) | ||||
| { | ||||
| 	if (ogg_codec_detect(&decoder, input_stream) != OGG_CODEC_VORBIS) | ||||
| 	if (ogg_codec_detect(&client, input_stream) != OGG_CODEC_VORBIS) | ||||
| 		return; | ||||
|  | ||||
| 	/* rewind the stream, because ogg_codec_detect() has | ||||
| @@ -314,7 +314,7 @@ vorbis_stream_decode(Decoder &decoder, | ||||
| 	} catch (const std::runtime_error &) { | ||||
| 	} | ||||
|  | ||||
| 	DecoderReader reader(decoder, input_stream); | ||||
| 	DecoderReader reader(client, input_stream); | ||||
| 	VorbisDecoder d(reader); | ||||
|  | ||||
| 	while (true) { | ||||
| @@ -323,10 +323,10 @@ vorbis_stream_decode(Decoder &decoder, | ||||
| 			break; | ||||
| 		} catch (DecoderCommand cmd) { | ||||
| 			if (cmd == DecoderCommand::SEEK) { | ||||
| 				if (d.Seek(decoder_seek_where_frame(decoder))) | ||||
| 					decoder_command_finished(decoder); | ||||
| 				if (d.Seek(decoder_seek_where_frame(client))) | ||||
| 					decoder_command_finished(client); | ||||
| 				else | ||||
| 					decoder_seek_error(decoder); | ||||
| 					decoder_seek_error(client); | ||||
| 			} else if (cmd != DecoderCommand::NONE) | ||||
| 				break; | ||||
| 		} | ||||
|   | ||||
| @@ -141,7 +141,7 @@ wavpack_bits_to_sample_format(bool is_float, int bytes_per_sample) | ||||
|  * Requires an already opened WavpackContext. | ||||
|  */ | ||||
| static void | ||||
| wavpack_decode(Decoder &decoder, WavpackContext *wpc, bool can_seek) | ||||
| wavpack_decode(DecoderClient &client, WavpackContext *wpc, bool can_seek) | ||||
| { | ||||
| 	bool is_float = (WavpackGetMode(wpc) & MODE_FLOAT) != 0; | ||||
| 	SampleFormat sample_format = | ||||
| @@ -168,21 +168,21 @@ wavpack_decode(Decoder &decoder, WavpackContext *wpc, bool can_seek) | ||||
| 	const uint32_t samples_requested = ARRAY_SIZE(chunk) / | ||||
| 		audio_format.channels; | ||||
|  | ||||
| 	decoder_initialized(decoder, audio_format, can_seek, total_time); | ||||
| 	decoder_initialized(client, audio_format, can_seek, total_time); | ||||
|  | ||||
| 	DecoderCommand cmd = decoder_get_command(decoder); | ||||
| 	DecoderCommand cmd = decoder_get_command(client); | ||||
| 	while (cmd != DecoderCommand::STOP) { | ||||
| 		if (cmd == DecoderCommand::SEEK) { | ||||
| 			if (can_seek) { | ||||
| 				auto where = decoder_seek_where_frame(decoder); | ||||
| 				auto where = decoder_seek_where_frame(client); | ||||
|  | ||||
| 				if (WavpackSeekSample(wpc, where)) { | ||||
| 					decoder_command_finished(decoder); | ||||
| 					decoder_command_finished(client); | ||||
| 				} else { | ||||
| 					decoder_seek_error(decoder); | ||||
| 					decoder_seek_error(client); | ||||
| 				} | ||||
| 			} else { | ||||
| 				decoder_seek_error(decoder); | ||||
| 				decoder_seek_error(client); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @@ -196,7 +196,7 @@ wavpack_decode(Decoder &decoder, WavpackContext *wpc, bool can_seek) | ||||
| 		format_samples(bytes_per_sample, chunk, | ||||
| 			       samples_got * audio_format.channels); | ||||
|  | ||||
| 		cmd = decoder_data(decoder, nullptr, chunk, | ||||
| 		cmd = decoder_data(client, nullptr, chunk, | ||||
| 				   samples_got * output_sample_size, | ||||
| 				   bitrate); | ||||
| 	} | ||||
| @@ -323,13 +323,13 @@ wavpack_scan_file(Path path_fs, | ||||
|  | ||||
| /* This struct is needed for per-stream last_byte storage. */ | ||||
| struct WavpackInput { | ||||
| 	Decoder &decoder; | ||||
| 	DecoderClient &client; | ||||
| 	InputStream &is; | ||||
| 	/* Needed for push_back_byte() */ | ||||
| 	int last_byte; | ||||
|  | ||||
| 	constexpr WavpackInput(Decoder &_decoder, InputStream &_is) | ||||
| 		:decoder(_decoder), is(_is), last_byte(EOF) {} | ||||
| 	constexpr WavpackInput(DecoderClient &_client, InputStream &_is) | ||||
| 		:client(_client), is(_is), last_byte(EOF) {} | ||||
|  | ||||
| 	int32_t ReadBytes(void *data, size_t bcount); | ||||
| }; | ||||
| @@ -366,7 +366,7 @@ WavpackInput::ReadBytes(void *data, size_t bcount) | ||||
| 	/* wavpack fails if we return a partial read, so we just wait | ||||
| 	   until the buffer is full */ | ||||
| 	while (bcount > 0) { | ||||
| 		size_t nbytes = decoder_read(&decoder, is, buf, bcount); | ||||
| 		size_t nbytes = decoder_read(&client, is, buf, bcount); | ||||
| 		if (nbytes == 0) { | ||||
| 			/* EOF, error or a decoder command */ | ||||
| 			break; | ||||
| @@ -481,7 +481,7 @@ static WavpackStreamReader mpd_is_reader = { | ||||
| }; | ||||
|  | ||||
| static InputStreamPtr | ||||
| wavpack_open_wvc(Decoder &decoder, const char *uri) | ||||
| wavpack_open_wvc(DecoderClient &client, const char *uri) | ||||
| { | ||||
| 	/* | ||||
| 	 * As we use dc->utf8url, this function will be bad for | ||||
| @@ -496,7 +496,7 @@ wavpack_open_wvc(Decoder &decoder, const char *uri) | ||||
| 	}; | ||||
|  | ||||
| 	try { | ||||
| 		return decoder_open_uri(decoder, uri); | ||||
| 		return decoder_open_uri(client, uri); | ||||
| 	} catch (const std::runtime_error &) { | ||||
| 		return nullptr; | ||||
| 	} | ||||
| @@ -506,25 +506,25 @@ wavpack_open_wvc(Decoder &decoder, const char *uri) | ||||
|  * Decodes a stream. | ||||
|  */ | ||||
| static void | ||||
| wavpack_streamdecode(Decoder &decoder, InputStream &is) | ||||
| wavpack_streamdecode(DecoderClient &client, InputStream &is) | ||||
| { | ||||
| 	int open_flags = OPEN_NORMALIZE; | ||||
| 	bool can_seek = is.IsSeekable(); | ||||
|  | ||||
| 	std::unique_ptr<WavpackInput> wvc; | ||||
| 	auto is_wvc = wavpack_open_wvc(decoder, is.GetURI()); | ||||
| 	auto is_wvc = wavpack_open_wvc(client, is.GetURI()); | ||||
| 	if (is_wvc) { | ||||
| 		open_flags |= OPEN_WVC; | ||||
| 		can_seek &= wvc->is.IsSeekable(); | ||||
|  | ||||
| 		wvc.reset(new WavpackInput(decoder, *is_wvc)); | ||||
| 		wvc.reset(new WavpackInput(client, *is_wvc)); | ||||
| 	} | ||||
|  | ||||
| 	if (!can_seek) { | ||||
| 		open_flags |= OPEN_STREAMING; | ||||
| 	} | ||||
|  | ||||
| 	WavpackInput isp(decoder, is); | ||||
| 	WavpackInput isp(client, is); | ||||
|  | ||||
| 	char error[ERRORLEN]; | ||||
| 	WavpackContext *wpc = | ||||
| @@ -541,14 +541,14 @@ wavpack_streamdecode(Decoder &decoder, InputStream &is) | ||||
| 		WavpackCloseFile(wpc); | ||||
| 	}; | ||||
|  | ||||
| 	wavpack_decode(decoder, wpc, can_seek); | ||||
| 	wavpack_decode(client, wpc, can_seek); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Decodes a file. | ||||
|  */ | ||||
| static void | ||||
| wavpack_filedecode(Decoder &decoder, Path path_fs) | ||||
| wavpack_filedecode(DecoderClient &client, Path path_fs) | ||||
| { | ||||
| 	char error[ERRORLEN]; | ||||
| 	WavpackContext *wpc = WavpackOpenFileInput(path_fs.c_str(), error, | ||||
| @@ -563,9 +563,9 @@ wavpack_filedecode(Decoder &decoder, Path path_fs) | ||||
|  | ||||
| 	ReplayGainInfo rgi; | ||||
| 	if (wavpack_replaygain(rgi, wpc)) | ||||
| 		decoder_replay_gain(decoder, &rgi); | ||||
| 		decoder_replay_gain(client, &rgi); | ||||
|  | ||||
| 	wavpack_decode(decoder, wpc, true); | ||||
| 	wavpack_decode(client, wpc, true); | ||||
|  | ||||
| 	WavpackCloseFile(wpc); | ||||
| } | ||||
|   | ||||
| @@ -61,7 +61,7 @@ wildmidi_finish(void) | ||||
| } | ||||
|  | ||||
| static DecoderCommand | ||||
| wildmidi_output(Decoder &decoder, midi *wm) | ||||
| wildmidi_output(DecoderClient &client, midi *wm) | ||||
| { | ||||
| #ifdef LIBWILDMIDI_VER_MAJOR | ||||
| 	/* WildMidi 0.4 has switched from "char*" to "int8_t*" */ | ||||
| @@ -75,11 +75,11 @@ wildmidi_output(Decoder &decoder, midi *wm) | ||||
| 	if (length <= 0) | ||||
| 		return DecoderCommand::STOP; | ||||
|  | ||||
| 	return decoder_data(decoder, nullptr, buffer, length, 0); | ||||
| 	return decoder_data(client, nullptr, buffer, length, 0); | ||||
| } | ||||
|  | ||||
| static void | ||||
| wildmidi_file_decode(Decoder &decoder, Path path_fs) | ||||
| wildmidi_file_decode(DecoderClient &client, Path path_fs) | ||||
| { | ||||
| 	static constexpr AudioFormat audio_format = { | ||||
| 		WILDMIDI_SAMPLE_RATE, | ||||
| @@ -103,7 +103,7 @@ wildmidi_file_decode(Decoder &decoder, Path path_fs) | ||||
| 		SongTime::FromScale<uint64_t>(info->approx_total_samples, | ||||
| 					      WILDMIDI_SAMPLE_RATE); | ||||
|  | ||||
| 	decoder_initialized(decoder, audio_format, true, duration); | ||||
| 	decoder_initialized(client, audio_format, true, duration); | ||||
|  | ||||
| 	DecoderCommand cmd; | ||||
| 	do { | ||||
| @@ -111,14 +111,14 @@ wildmidi_file_decode(Decoder &decoder, Path path_fs) | ||||
| 		if (info == nullptr) | ||||
| 			break; | ||||
|  | ||||
| 		cmd = wildmidi_output(decoder, wm); | ||||
| 		cmd = wildmidi_output(client, wm); | ||||
|  | ||||
| 		if (cmd == DecoderCommand::SEEK) { | ||||
| 			unsigned long seek_where = | ||||
| 				decoder_seek_where_frame(decoder); | ||||
| 				decoder_seek_where_frame(client); | ||||
|  | ||||
| 			WildMidi_FastSeek(wm, &seek_where); | ||||
| 			decoder_command_finished(decoder); | ||||
| 			decoder_command_finished(client); | ||||
| 			cmd = DecoderCommand::NONE; | ||||
| 		} | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Max Kellermann
					Max Kellermann