audio_format: wildcards allowed in audio_format configuration

An asterisk means that this attribute should not be enforced, and
stays whatever it used to be.  This way, some configuration values
work like masks.
This commit is contained in:
Max Kellermann 2009-10-21 23:01:04 +02:00
parent a5c4566fa1
commit 9526fdbe73
14 changed files with 118 additions and 30 deletions

1
NEWS
View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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);

View File

@ -90,6 +90,27 @@ static inline bool audio_format_defined(const struct audio_format *af)
return af->sample_rate != 0;
}
/**
* 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.
*
@ -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.
*/

View File

@ -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) {

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);