aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--doc/mpd.conf.54
-rw-r--r--doc/user.xml17
-rw-r--r--src/audio.c7
-rw-r--r--src/audio_format.h47
-rw-r--r--src/audio_parser.c32
-rw-r--r--src/audio_parser.h3
-rw-r--r--src/output/shout_plugin.c9
-rw-r--r--src/output_init.c5
-rw-r--r--src/output_thread.c11
-rw-r--r--test/run_encoder.c3
-rw-r--r--test/run_filter.c3
-rw-r--r--test/run_output.c3
-rw-r--r--test/software_volume.c3
14 files changed, 118 insertions, 30 deletions
diff --git a/NEWS b/NEWS
index 6349f16d..f8b02bae 100644
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,7 @@ ver 0.16 (20??/??/??)
- pulse: connect to server on MPD startup, implement pause
- jack: don't disconnect during pause
- jack: connect to server on MPD startup
+ - wildcards allowed in audio_format configuration
* mixers:
- removed support for legacy mixer configuration
- reimplemented software volume as mixer+filter plugin
diff --git a/doc/mpd.conf.5 b/doc/mpd.conf.5
index 0784ea39..6bbd7e78 100644
--- a/doc/mpd.conf.5
+++ b/doc/mpd.conf.5
@@ -129,6 +129,8 @@ audio that is sent to each audio output. Note that audio outputs may specify
their own audio format which will be used for actual output to the audio
device. An example is "44100:16:2" for 44100Hz, 16 bits, and 2 channels. The
default is to use the audio format of the input file.
+Any of the three attributes may be an asterisk to specify that this
+attribute should not be enforced
.TP
.B samplerate_converter <integer or prefix>
This specifies the libsamplerate converter to use. The supplied value should
@@ -261,6 +263,8 @@ This specifies the sample rate, bits per sample, and number of channels of
audio that is sent to the audio output device. See documentation for the
\fBaudio_output_format\fP parameter for more details. The default is to use
whatever audio format is passed to the audio output.
+Any of the three attributes may be an asterisk to specify that this
+attribute should not be enforced
.SH OPTIONAL ALSA OUTPUT PARAMETERS
.TP
.B device <dev>
diff --git a/doc/user.xml b/doc/user.xml
index ca63eccd..8111482d 100644
--- a/doc/user.xml
+++ b/doc/user.xml
@@ -300,10 +300,19 @@ cd mpd-version</programlisting>
<varname>format</varname>
</entry>
<entry>
- Always open the audio output with the specified audio
- format (samplerate:bits:channels), regardless of the
- format of the input file. This is optional for most
- plugins.
+ <para>
+ Always open the audio output with the specified audio
+ format (samplerate:bits:channels), regardless of the
+ format of the input file. This is optional for most
+ plugins.
+ </para>
+ <para>
+ Any of the three attributes may be an asterisk to
+ specify that this attribute should not be enforced,
+ example: <parameter>48000:16:*</parameter>.
+ <parameter>*:*:*</parameter> is equal to not having
+ a <varname>format</varname> specification.
+ </para>
</entry>
</row>
<row>
diff --git a/src/audio.c b/src/audio.c
index fb471272..13f128ee 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -35,9 +35,8 @@ static struct audio_format configured_audio_format;
void getOutputAudioFormat(const struct audio_format *inAudioFormat,
struct audio_format *outAudioFormat)
{
- *outAudioFormat = audio_format_defined(&configured_audio_format)
- ? configured_audio_format
- : *inAudioFormat;
+ *outAudioFormat = *inAudioFormat;
+ audio_format_mask_apply(outAudioFormat, &configured_audio_format);
}
void initAudioConfig(void)
@@ -50,7 +49,7 @@ void initAudioConfig(void)
return;
ret = audio_format_parse(&configured_audio_format, param->value,
- &error);
+ true, &error);
if (!ret)
g_error("error parsing \"%s\" at line %i: %s",
CONF_AUDIO_OUTPUT_FORMAT, param->line, error->message);
diff --git a/src/audio_format.h b/src/audio_format.h
index a88fc3a4..a4f5ba2e 100644
--- a/src/audio_format.h
+++ b/src/audio_format.h
@@ -91,6 +91,27 @@ static inline bool audio_format_defined(const struct audio_format *af)
}
/**
+ * Checks whether the specified #audio_format object is full, i.e. all
+ * attributes are defined. This is more complete than
+ * audio_format_defined(), but slower.
+ */
+static inline bool
+audio_format_fully_defined(const struct audio_format *af)
+{
+ return af->sample_rate != 0 && af->bits != 0 && af->channels != 0;
+}
+
+/**
+ * Checks whether the specified #audio_format object has at least one
+ * defined value.
+ */
+static inline bool
+audio_format_mask_defined(const struct audio_format *af)
+{
+ return af->sample_rate != 0 || af->bits != 0 || af->channels != 0;
+}
+
+/**
* Checks whether the sample rate is valid.
*
* @param sample_rate the sample rate in Hz
@@ -132,6 +153,18 @@ static inline bool audio_format_valid(const struct audio_format *af)
audio_valid_channel_count(af->channels);
}
+/**
+ * Returns false if the format mask is not valid for playback with
+ * MPD. This function performs some basic validity checks.
+ */
+static inline bool audio_format_mask_valid(const struct audio_format *af)
+{
+ return (af->sample_rate == 0 ||
+ audio_valid_sample_rate(af->sample_rate)) &&
+ (af->bits == 0 || audio_valid_sample_format(af->bits)) &&
+ (af->channels == 0 || audio_valid_channel_count(af->channels));
+}
+
static inline bool audio_format_equals(const struct audio_format *a,
const struct audio_format *b)
{
@@ -141,6 +174,20 @@ static inline bool audio_format_equals(const struct audio_format *a,
a->reverse_endian == b->reverse_endian;
}
+static inline void
+audio_format_mask_apply(struct audio_format *af,
+ const struct audio_format *mask)
+{
+ if (mask->sample_rate != 0)
+ af->sample_rate = mask->sample_rate;
+
+ if (mask->bits != 0)
+ af->bits = mask->bits;
+
+ if (mask->channels != 0)
+ af->channels = mask->channels;
+}
+
/**
* Returns the size of each (mono) sample in bytes.
*/
diff --git a/src/audio_parser.c b/src/audio_parser.c
index 0b3474ab..7c0d45dd 100644
--- a/src/audio_parser.c
+++ b/src/audio_parser.c
@@ -37,12 +37,18 @@ audio_parser_quark(void)
}
static bool
-parse_sample_rate(const char *src, uint32_t *sample_rate_r,
+parse_sample_rate(const char *src, bool mask, uint32_t *sample_rate_r,
const char **endptr_r, GError **error_r)
{
unsigned long value;
char *endptr;
+ if (mask && *src == '*') {
+ *sample_rate_r = 0;
+ *endptr_r = src + 1;
+ return true;
+ }
+
value = strtoul(src, &endptr, 10);
if (endptr == src) {
g_set_error(error_r, audio_parser_quark(), 0,
@@ -60,12 +66,18 @@ parse_sample_rate(const char *src, uint32_t *sample_rate_r,
}
static bool
-parse_sample_format(const char *src, uint8_t *bits_r,
+parse_sample_format(const char *src, bool mask, uint8_t *bits_r,
const char **endptr_r, GError **error_r)
{
unsigned long value;
char *endptr;
+ if (mask && *src == '*') {
+ *bits_r = 0;
+ *endptr_r = src + 1;
+ return true;
+ }
+
value = strtoul(src, &endptr, 10);
if (endptr == src) {
g_set_error(error_r, audio_parser_quark(), 0,
@@ -83,12 +95,18 @@ parse_sample_format(const char *src, uint8_t *bits_r,
}
static bool
-parse_channel_count(const char *src, uint8_t *channels_r,
+parse_channel_count(const char *src, bool mask, uint8_t *channels_r,
const char **endptr_r, GError **error_r)
{
unsigned long value;
char *endptr;
+ if (mask && *src == '*') {
+ *channels_r = 0;
+ *endptr_r = src + 1;
+ return true;
+ }
+
value = strtoul(src, &endptr, 10);
if (endptr == src) {
g_set_error(error_r, audio_parser_quark(), 0,
@@ -107,7 +125,7 @@ parse_channel_count(const char *src, uint8_t *channels_r,
bool
audio_format_parse(struct audio_format *dest, const char *src,
- GError **error_r)
+ bool mask, GError **error_r)
{
uint32_t rate;
uint8_t bits, channels;
@@ -116,7 +134,7 @@ audio_format_parse(struct audio_format *dest, const char *src,
/* parse sample rate */
- if (!parse_sample_rate(src, &rate, &src, error_r))
+ if (!parse_sample_rate(src, mask, &rate, &src, error_r))
return false;
if (*src++ != ':') {
@@ -127,7 +145,7 @@ audio_format_parse(struct audio_format *dest, const char *src,
/* parse sample format */
- if (!parse_sample_format(src, &bits, &src, error_r))
+ if (!parse_sample_format(src, mask, &bits, &src, error_r))
return false;
if (*src++ != ':') {
@@ -138,7 +156,7 @@ audio_format_parse(struct audio_format *dest, const char *src,
/* parse channel count */
- if (!parse_channel_count(src, &channels, &src, error_r))
+ if (!parse_channel_count(src, mask, &channels, &src, error_r))
return false;
if (*src != 0) {
diff --git a/src/audio_parser.h b/src/audio_parser.h
index 1d821eaf..d50c1748 100644
--- a/src/audio_parser.h
+++ b/src/audio_parser.h
@@ -37,12 +37,13 @@ struct audio_format;
*
* @param dest the destination #audio_format struct
* @param src the input string
+ * @param mask if true, then "*" is allowed for any number of items
* @param error_r location to store the error occuring, or NULL to
* ignore errors
* @return true on success
*/
bool
audio_format_parse(struct audio_format *dest, const char *src,
- GError **error_r);
+ bool mask, GError **error_r);
#endif
diff --git a/src/output/shout_plugin.c b/src/output/shout_plugin.c
index f1b21bb3..da90efd2 100644
--- a/src/output/shout_plugin.c
+++ b/src/output/shout_plugin.c
@@ -126,6 +126,13 @@ my_shout_init_driver(const struct audio_format *audio_format,
struct block_param *block_param;
int public;
+ if (audio_format == NULL ||
+ !audio_format_fully_defined(audio_format)) {
+ g_set_error(error, shout_output_quark(), 0,
+ "Need full audio format specification");
+ return NULL;
+ }
+
sd = new_shout_data();
if (shout_init_count == 0)
@@ -191,8 +198,6 @@ my_shout_init_driver(const struct audio_format *audio_format,
}
}
- check_block_param("format");
-
encoding = config_get_block_string(param, "encoding", "ogg");
encoder_plugin = shout_encoder_plugin_get(encoding);
if (encoder_plugin == NULL) {
diff --git a/src/output_init.c b/src/output_init.c
index f097f2c2..745b63e3 100644
--- a/src/output_init.c
+++ b/src/output_init.c
@@ -157,7 +157,7 @@ audio_output_init(struct audio_output *ao, const struct config_param *param,
if (p != NULL) {
bool success =
audio_format_parse(&ao->config_audio_format,
- p, error_r);
+ p, true, error_r);
if (!success)
return false;
} else
@@ -195,8 +195,7 @@ audio_output_init(struct audio_output *ao, const struct config_param *param,
ao->mutex = g_mutex_new();
ao->data = ao_plugin_init(plugin,
- audio_format_defined(&ao->config_audio_format)
- ? &ao->config_audio_format : NULL,
+ &ao->config_audio_format,
param, error_r);
if (ao->data == NULL)
return false;
diff --git a/src/output_thread.c b/src/output_thread.c
index dd97d88b..9eb2478b 100644
--- a/src/output_thread.c
+++ b/src/output_thread.c
@@ -67,10 +67,9 @@ ao_open(struct audio_output *ao)
return;
}
- if (audio_format_defined(&ao->config_audio_format))
- ao->out_audio_format = ao->config_audio_format;
- else
- ao->out_audio_format = *filter_audio_format;
+ ao->out_audio_format = *filter_audio_format;
+ audio_format_mask_apply(&ao->out_audio_format,
+ &ao->config_audio_format);
success = ao_plugin_open(ao->plugin, ao->data,
&ao->out_audio_format,
@@ -166,7 +165,7 @@ ao_reopen_filter(struct audio_output *ao)
static void
ao_reopen(struct audio_output *ao)
{
- if (!audio_format_defined(&ao->config_audio_format)) {
+ if (!audio_format_fully_defined(&ao->config_audio_format)) {
if (ao->open) {
const struct music_pipe *mp = ao->pipe;
ao_close(ao);
@@ -177,6 +176,8 @@ ao_reopen(struct audio_output *ao)
the output's open() method determine the effective
out_audio_format */
ao->out_audio_format = ao->in_audio_format;
+ audio_format_mask_apply(&ao->out_audio_format,
+ &ao->config_audio_format);
}
if (ao->open)
diff --git a/test/run_encoder.c b/test/run_encoder.c
index 787fb03c..b953bcd9 100644
--- a/test/run_encoder.c
+++ b/test/run_encoder.c
@@ -86,7 +86,8 @@ int main(int argc, char **argv)
/* open the encoder */
if (argc > 2) {
- ret = audio_format_parse(&audio_format, argv[2], &error);
+ ret = audio_format_parse(&audio_format, argv[2],
+ false, &error);
if (!ret) {
g_printerr("Failed to parse audio format: %s\n",
error->message);
diff --git a/test/run_filter.c b/test/run_filter.c
index ed2b904c..3c4b7612 100644
--- a/test/run_filter.c
+++ b/test/run_filter.c
@@ -100,7 +100,8 @@ int main(int argc, char **argv)
/* parse the audio format */
if (argc > 3) {
- success = audio_format_parse(&audio_format, argv[3], &error);
+ success = audio_format_parse(&audio_format, argv[3],
+ false, &error);
if (!success) {
g_printerr("Failed to parse audio format: %s\n",
error->message);
diff --git a/test/run_output.c b/test/run_output.c
index 3731b6c0..238e16e5 100644
--- a/test/run_output.c
+++ b/test/run_output.c
@@ -143,7 +143,8 @@ int main(int argc, char **argv)
/* parse the audio format */
if (argc > 3) {
- success = audio_format_parse(&audio_format, argv[3], &error);
+ success = audio_format_parse(&audio_format, argv[3],
+ false, &error);
if (!success) {
g_printerr("Failed to parse audio format: %s\n",
error->message);
diff --git a/test/software_volume.c b/test/software_volume.c
index 9e8c8e7d..5d551b1f 100644
--- a/test/software_volume.c
+++ b/test/software_volume.c
@@ -46,7 +46,8 @@ int main(int argc, char **argv)
}
if (argc > 1) {
- ret = audio_format_parse(&audio_format, argv[1], &error);
+ ret = audio_format_parse(&audio_format, argv[1],
+ false, &error);
if (!ret) {
g_printerr("Failed to parse audio format: %s\n",
error->message);