Commit 13001c01 authored by Max Kellermann's avatar Max Kellermann

AudioParser: throw exception on error

parent 1b39efb6
...@@ -2023,6 +2023,7 @@ test_run_avahi_LDADD = \ ...@@ -2023,6 +2023,7 @@ test_run_avahi_LDADD = \
$(AVAHI_LIBS) $(AVAHI_LIBS)
test_run_normalize_SOURCES = test/run_normalize.cxx \ test_run_normalize_SOURCES = test/run_normalize.cxx \
src/Log.cxx src/LogBackend.cxx \
src/CheckAudioFormat.cxx \ src/CheckAudioFormat.cxx \
src/AudioCompress/compress.c \ src/AudioCompress/compress.c \
src/AudioParser.cxx src/AudioParser.cxx
......
...@@ -24,8 +24,7 @@ ...@@ -24,8 +24,7 @@
#include "config/Param.hxx" #include "config/Param.hxx"
#include "config/ConfigGlobal.hxx" #include "config/ConfigGlobal.hxx"
#include "config/ConfigOption.hxx" #include "config/ConfigOption.hxx"
#include "util/Error.hxx" #include "util/RuntimeError.hxx"
#include "system/FatalError.hxx"
static AudioFormat configured_audio_format; static AudioFormat configured_audio_format;
...@@ -44,9 +43,10 @@ void initAudioConfig(void) ...@@ -44,9 +43,10 @@ void initAudioConfig(void)
if (param == nullptr) if (param == nullptr)
return; return;
Error error; try {
if (!audio_format_parse(configured_audio_format, param->value.c_str(), configured_audio_format = ParseAudioFormat(param->value.c_str(), true);
true, error)) } catch (const std::runtime_error &) {
FormatFatalError("error parsing line %i: %s", std::throw_with_nested(FormatRuntimeError("error parsing line %i",
param->line, error.GetMessage()); param->line));
}
} }
...@@ -25,73 +25,59 @@ ...@@ -25,73 +25,59 @@
#include "config.h" #include "config.h"
#include "AudioParser.hxx" #include "AudioParser.hxx"
#include "AudioFormat.hxx" #include "AudioFormat.hxx"
#include "CheckAudioFormat.hxx" #include "util/RuntimeError.hxx"
#include "util/Error.hxx"
#include "Compiler.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
static bool static uint32_t
parse_sample_rate(const char *src, bool mask, uint32_t *sample_rate_r, ParseSampleRate(const char *src, bool mask, const char **endptr_r)
const char **endptr_r, Error &error)
{ {
unsigned long value; unsigned long value;
char *endptr; char *endptr;
if (mask && *src == '*') { if (mask && *src == '*') {
*sample_rate_r = 0;
*endptr_r = src + 1; *endptr_r = src + 1;
return true; return 0;
} }
value = strtoul(src, &endptr, 10); value = strtoul(src, &endptr, 10);
if (endptr == src) { if (endptr == src) {
error.Set(audio_format_domain, throw std::runtime_error("Failed to parse the sample rate");
"Failed to parse the sample rate"); } else if (!audio_valid_sample_rate(value))
return false; throw FormatRuntimeError("Invalid sample rate: %lu",
} else if (!audio_check_sample_rate(value, error)) value);
return false;
*sample_rate_r = value;
*endptr_r = endptr; *endptr_r = endptr;
return true; return value;
} }
static bool static SampleFormat
parse_sample_format(const char *src, bool mask, ParseSampleFormat(const char *src, bool mask, const char **endptr_r)
SampleFormat *sample_format_r,
const char **endptr_r, Error &error)
{ {
unsigned long value; unsigned long value;
char *endptr; char *endptr;
SampleFormat sample_format; SampleFormat sample_format;
if (mask && *src == '*') { if (mask && *src == '*') {
*sample_format_r = SampleFormat::UNDEFINED;
*endptr_r = src + 1; *endptr_r = src + 1;
return true; return SampleFormat::UNDEFINED;
} }
if (*src == 'f') { if (*src == 'f') {
*sample_format_r = SampleFormat::FLOAT;
*endptr_r = src + 1; *endptr_r = src + 1;
return true; return SampleFormat::FLOAT;
} }
if (memcmp(src, "dsd", 3) == 0) { if (memcmp(src, "dsd", 3) == 0) {
*sample_format_r = SampleFormat::DSD;
*endptr_r = src + 3; *endptr_r = src + 3;
return true; return SampleFormat::DSD;
} }
value = strtoul(src, &endptr, 10); value = strtoul(src, &endptr, 10);
if (endptr == src) { if (endptr == src)
error.Set(audio_format_domain, throw std::runtime_error("Failed to parse the sample format");
"Failed to parse the sample format");
return false;
}
switch (value) { switch (value) {
case 8: case 8:
...@@ -115,99 +101,65 @@ parse_sample_format(const char *src, bool mask, ...@@ -115,99 +101,65 @@ parse_sample_format(const char *src, bool mask,
break; break;
default: default:
error.Format(audio_format_domain, throw FormatRuntimeError("Invalid sample format: %lu", value);
"Invalid sample format: %lu", value);
return false;
} }
assert(audio_valid_sample_format(sample_format)); assert(audio_valid_sample_format(sample_format));
*sample_format_r = sample_format;
*endptr_r = endptr; *endptr_r = endptr;
return true; return sample_format;
} }
static bool static uint8_t
parse_channel_count(const char *src, bool mask, uint8_t *channels_r, ParseChannelCount(const char *src, bool mask, const char **endptr_r)
const char **endptr_r, Error &error)
{ {
unsigned long value; unsigned long value;
char *endptr; char *endptr;
if (mask && *src == '*') { if (mask && *src == '*') {
*channels_r = 0;
*endptr_r = src + 1; *endptr_r = src + 1;
return true; return 0;
} }
value = strtoul(src, &endptr, 10); value = strtoul(src, &endptr, 10);
if (endptr == src) { if (endptr == src)
error.Set(audio_format_domain, throw std::runtime_error("Failed to parse the channel count");
"Failed to parse the channel count"); else if (!audio_valid_channel_count(value))
return false; throw FormatRuntimeError("Invalid channel count: %u", value);
} else if (!audio_check_channel_count(value, error))
return false;
*channels_r = value;
*endptr_r = endptr; *endptr_r = endptr;
return true; return value;
} }
bool AudioFormat
audio_format_parse(AudioFormat &dest, const char *src, ParseAudioFormat(const char *src, bool mask)
bool mask, Error &error)
{ {
uint32_t rate; AudioFormat dest;
SampleFormat sample_format;
uint8_t channels;
dest.Clear(); dest.Clear();
/* parse sample rate */ /* parse sample rate */
#if GCC_CHECK_VERSION(4,7) dest.sample_rate = ParseSampleRate(src, mask, &src);
/* workaround -Wmaybe-uninitialized false positive */
rate = 0;
#endif
if (!parse_sample_rate(src, mask, &rate, &src, error)) if (*src++ != ':')
return false; throw std::runtime_error("Sample format missing");
if (*src++ != ':') {
error.Set(audio_format_domain, "Sample format missing");
return false;
}
/* parse sample format */ /* parse sample format */
#if GCC_CHECK_VERSION(4,7) dest.format = ParseSampleFormat(src, mask, &src);
/* workaround -Wmaybe-uninitialized false positive */
sample_format = SampleFormat::UNDEFINED;
#endif
if (!parse_sample_format(src, mask, &sample_format, &src, error))
return false;
if (*src++ != ':') { if (*src++ != ':')
error.Set(audio_format_domain, "Channel count missing"); throw std::runtime_error("Channel count missing");
return false;
}
/* parse channel count */ /* parse channel count */
if (!parse_channel_count(src, mask, &channels, &src, error)) dest.channels = ParseChannelCount(src, mask, &src);
return false;
if (*src != 0) { if (*src != 0)
error.Format(audio_format_domain, throw FormatRuntimeError("Extra data after channel count: %s", src);
"Extra data after channel count: %s", src);
return false;
}
dest = AudioFormat(rate, sample_format, channels);
assert(mask assert(mask
? dest.IsMaskValid() ? dest.IsMaskValid()
: dest.IsValid()); : dest.IsValid());
return dest;
return true;
} }
...@@ -25,22 +25,21 @@ ...@@ -25,22 +25,21 @@
#ifndef MPD_AUDIO_PARSER_HXX #ifndef MPD_AUDIO_PARSER_HXX
#define MPD_AUDIO_PARSER_HXX #define MPD_AUDIO_PARSER_HXX
#include "Compiler.h"
struct AudioFormat; struct AudioFormat;
class Error;
/** /**
* Parses a string in the form "SAMPLE_RATE:BITS:CHANNELS" into an * Parses a string in the form "SAMPLE_RATE:BITS:CHANNELS" into an
* #AudioFormat. * #AudioFormat.
* *
* @param dest the destination #audio_format struct * Throws #std::runtime_error on error.
*
* @param src the input string * @param src the input string
* @param mask if true, then "*" is allowed for any number of items * @param mask if true, then "*" is allowed for any number of items
* @param error location to store the error occurring, or NULL to
* ignore errors
* @return true on success
*/ */
bool gcc_pure
audio_format_parse(AudioFormat &dest, const char *src, AudioFormat
bool mask, Error &error); ParseAudioFormat(const char *src, bool mask);
#endif #endif
...@@ -162,13 +162,9 @@ AudioOutput::Configure(const ConfigBlock &block, Error &error) ...@@ -162,13 +162,9 @@ AudioOutput::Configure(const ConfigBlock &block, Error &error)
} }
const char *p = block.GetBlockValue(AUDIO_OUTPUT_FORMAT); const char *p = block.GetBlockValue(AUDIO_OUTPUT_FORMAT);
if (p != nullptr) { if (p != nullptr)
bool success = config_audio_format = ParseAudioFormat(p, true);
audio_format_parse(config_audio_format, else
p, true, error);
if (!success)
return false;
} else
config_audio_format.Clear(); config_audio_format.Clear();
} else { } else {
name = "default detected output"; name = "default detected output";
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include "pcm/PcmConvert.hxx" #include "pcm/PcmConvert.hxx"
#include "util/ConstBuffer.hxx" #include "util/ConstBuffer.hxx"
#include "util/StaticFifoBuffer.hxx" #include "util/StaticFifoBuffer.hxx"
#include "util/Error.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <assert.h> #include <assert.h>
...@@ -41,29 +40,16 @@ ...@@ -41,29 +40,16 @@
int int
main(int argc, char **argv) main(int argc, char **argv)
try { try {
AudioFormat in_audio_format, out_audio_format;
if (argc != 3) { if (argc != 3) {
fprintf(stderr, fprintf(stderr,
"Usage: run_convert IN_FORMAT OUT_FORMAT <IN >OUT\n"); "Usage: run_convert IN_FORMAT OUT_FORMAT <IN >OUT\n");
return 1; return 1;
} }
Error error; const auto in_audio_format = ParseAudioFormat(argv[1], false);
if (!audio_format_parse(in_audio_format, argv[1], const auto out_audio_format_mask = ParseAudioFormat(argv[2], false);
false, error)) {
LogError(error, "Failed to parse audio format");
return EXIT_FAILURE;
}
AudioFormat out_audio_format_mask;
if (!audio_format_parse(out_audio_format_mask, argv[2],
true, error)) {
LogError(error, "Failed to parse audio format");
return EXIT_FAILURE;
}
out_audio_format = in_audio_format; auto out_audio_format = in_audio_format;
out_audio_format.ApplyMask(out_audio_format_mask); out_audio_format.ApplyMask(out_audio_format_mask);
const size_t in_frame_size = in_audio_format.GetFrameSize(); const size_t in_frame_size = in_audio_format.GetFrameSize();
......
...@@ -72,12 +72,8 @@ int main(int argc, char **argv) ...@@ -72,12 +72,8 @@ int main(int argc, char **argv)
/* open the encoder */ /* open the encoder */
AudioFormat audio_format(44100, SampleFormat::S16, 2); AudioFormat audio_format(44100, SampleFormat::S16, 2);
if (argc > 2) { if (argc > 2)
if (!audio_format_parse(audio_format, argv[2], false, error)) { audio_format = ParseAudioFormat(argv[2], false);
LogError(error, "Failed to parse audio format");
return EXIT_FAILURE;
}
}
std::unique_ptr<Encoder> encoder(p_encoder->Open(audio_format, error)); std::unique_ptr<Encoder> encoder(p_encoder->Open(audio_format, error));
if (encoder == nullptr) { if (encoder == nullptr) {
......
...@@ -27,12 +27,12 @@ ...@@ -27,12 +27,12 @@
#include "filter/FilterInternal.hxx" #include "filter/FilterInternal.hxx"
#include "pcm/Volume.hxx" #include "pcm/Volume.hxx"
#include "mixer/MixerControl.hxx" #include "mixer/MixerControl.hxx"
#include "util/Error.hxx"
#include "util/ConstBuffer.hxx" #include "util/ConstBuffer.hxx"
#include "system/FatalError.hxx" #include "system/FatalError.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <memory> #include <memory>
#include <stdexcept>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
...@@ -81,13 +81,8 @@ try { ...@@ -81,13 +81,8 @@ try {
/* parse the audio format */ /* parse the audio format */
if (argc > 3) { if (argc > 3)
Error error; audio_format = ParseAudioFormat(argv[3], false);
if (!audio_format_parse(audio_format, argv[3], false, error)) {
LogError(error, "Failed to parse audio format");
return EXIT_FAILURE;
}
}
/* initialize the filter */ /* initialize the filter */
......
...@@ -27,15 +27,18 @@ ...@@ -27,15 +27,18 @@
#include "AudioCompress/compress.h" #include "AudioCompress/compress.h"
#include "AudioParser.hxx" #include "AudioParser.hxx"
#include "AudioFormat.hxx" #include "AudioFormat.hxx"
#include "util/Error.hxx" #include "Log.hxx"
#include <stdexcept>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
int main(int argc, char **argv) int main(int argc, char **argv)
{ try {
struct Compressor *compressor; struct Compressor *compressor;
static char buffer[4096]; static char buffer[4096];
ssize_t nbytes; ssize_t nbytes;
...@@ -46,14 +49,8 @@ int main(int argc, char **argv) ...@@ -46,14 +49,8 @@ int main(int argc, char **argv)
} }
AudioFormat audio_format(48000, SampleFormat::S16, 2); AudioFormat audio_format(48000, SampleFormat::S16, 2);
if (argc > 1) { if (argc > 1)
Error error; audio_format = ParseAudioFormat(argv[1], false);
if (!audio_format_parse(audio_format, argv[1], false, error)) {
fprintf(stderr, "Failed to parse audio format: %s\n",
error.GetMessage());
return 1;
}
}
compressor = Compressor_new(0); compressor = Compressor_new(0);
...@@ -65,4 +62,8 @@ int main(int argc, char **argv) ...@@ -65,4 +62,8 @@ int main(int argc, char **argv)
} }
Compressor_delete(compressor); Compressor_delete(compressor);
return EXIT_SUCCESS;
} catch (const std::exception &e) {
LogError(e);
return EXIT_FAILURE;
} }
...@@ -175,12 +175,8 @@ try { ...@@ -175,12 +175,8 @@ try {
/* parse the audio format */ /* parse the audio format */
if (argc > 3) { if (argc > 3)
if (!audio_format_parse(audio_format, argv[3], false, error)) { audio_format = ParseAudioFormat(argv[3], false);
LogError(error, "Failed to parse audio format");
return EXIT_FAILURE;
}
}
/* do it */ /* do it */
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include "AudioParser.hxx" #include "AudioParser.hxx"
#include "AudioFormat.hxx" #include "AudioFormat.hxx"
#include "util/ConstBuffer.hxx" #include "util/ConstBuffer.hxx"
#include "util/Error.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <stdio.h> #include <stdio.h>
...@@ -47,14 +46,9 @@ try { ...@@ -47,14 +46,9 @@ try {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
Error error;
AudioFormat audio_format(48000, SampleFormat::S16, 2); AudioFormat audio_format(48000, SampleFormat::S16, 2);
if (argc > 1) { if (argc > 1)
if (!audio_format_parse(audio_format, argv[1], false, error)) { audio_format = ParseAudioFormat(argv[1], false);
LogError(error, "Failed to parse audio format");
return EXIT_FAILURE;
}
}
PcmVolume pv; PcmVolume pv;
pv.Open(audio_format.format); pv.Open(audio_format.format);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment