AudioParser: throw exception on error
This commit is contained in:
@@ -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 @@
|
|||||||
#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)
|
|||||||
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 @@
|
|||||||
#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,
|
|||||||
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))
|
if (*src++ != ':')
|
||||||
return false;
|
throw std::runtime_error("Channel count missing");
|
||||||
|
|
||||||
if (*src++ != ':') {
|
|
||||||
error.Set(audio_format_domain, "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 @@
|
|||||||
#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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 @@
|
|||||||
#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 @@
|
|||||||
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;
|
auto out_audio_format = in_audio_format;
|
||||||
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;
|
|
||||||
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)
|
|||||||
/* 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 @@
|
|||||||
#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 {
|
|||||||
|
|
||||||
/* 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 @@
|
|||||||
#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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Compressor_delete(compressor);
|
Compressor_delete(compressor);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
LogError(e);
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
@@ -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 @@
|
|||||||
#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 {
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user