pcm_resample: one-time global initialization
Load the samplerate_converter on MPD startup. Fail if the converter name is invalid.
This commit is contained in:
@@ -44,6 +44,7 @@
|
|||||||
#include "volume.h"
|
#include "volume.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "permission.h"
|
#include "permission.h"
|
||||||
|
#include "pcm_resample.h"
|
||||||
#include "replay_gain_config.h"
|
#include "replay_gain_config.h"
|
||||||
#include "decoder_list.h"
|
#include "decoder_list.h"
|
||||||
#include "input_init.h"
|
#include "input_init.h"
|
||||||
@@ -403,6 +404,13 @@ int mpd_main(int argc, char *argv[])
|
|||||||
#ifdef ENABLE_ARCHIVE
|
#ifdef ENABLE_ARCHIVE
|
||||||
archive_plugin_init_all();
|
archive_plugin_init_all();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!pcm_resample_global_init(&error)) {
|
||||||
|
g_warning("%s", error->message);
|
||||||
|
g_error_free(error);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
decoder_plugin_init_all();
|
decoder_plugin_init_all();
|
||||||
update_global_init();
|
update_global_init();
|
||||||
|
|
||||||
|
@@ -26,15 +26,36 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSAMPLERATE
|
||||||
|
static bool lsr_enabled;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIBSAMPLERATE
|
#ifdef HAVE_LIBSAMPLERATE
|
||||||
static bool
|
static bool
|
||||||
pcm_resample_lsr_enabled(void)
|
pcm_resample_lsr_enabled(void)
|
||||||
{
|
{
|
||||||
return strcmp(config_get_string(CONF_SAMPLERATE_CONVERTER, ""),
|
return lsr_enabled;
|
||||||
"internal") != 0;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool
|
||||||
|
pcm_resample_global_init(GError **error_r)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LIBSAMPLERATE
|
||||||
|
const char *converter =
|
||||||
|
config_get_string(CONF_SAMPLERATE_CONVERTER, "");
|
||||||
|
|
||||||
|
lsr_enabled = strcmp(converter, "internal") != 0;
|
||||||
|
if (lsr_enabled)
|
||||||
|
return pcm_resample_lsr_global_init(converter, error_r);
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
(void)error_r;
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void pcm_resample_init(struct pcm_resample_state *state)
|
void pcm_resample_init(struct pcm_resample_state *state)
|
||||||
{
|
{
|
||||||
memset(state, 0, sizeof(*state));
|
memset(state, 0, sizeof(*state));
|
||||||
|
@@ -54,6 +54,9 @@ struct pcm_resample_state {
|
|||||||
struct pcm_buffer buffer;
|
struct pcm_buffer buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
pcm_resample_global_init(GError **error_r);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a pcm_resample_state object.
|
* Initializes a pcm_resample_state object.
|
||||||
*/
|
*/
|
||||||
|
@@ -32,6 +32,9 @@
|
|||||||
|
|
||||||
#ifdef HAVE_LIBSAMPLERATE
|
#ifdef HAVE_LIBSAMPLERATE
|
||||||
|
|
||||||
|
bool
|
||||||
|
pcm_resample_lsr_global_init(const char *converter, GError **error_r);
|
||||||
|
|
||||||
void
|
void
|
||||||
pcm_resample_lsr_deinit(struct pcm_resample_state *state);
|
pcm_resample_lsr_deinit(struct pcm_resample_state *state);
|
||||||
|
|
||||||
|
@@ -30,12 +30,59 @@
|
|||||||
#undef G_LOG_DOMAIN
|
#undef G_LOG_DOMAIN
|
||||||
#define G_LOG_DOMAIN "pcm"
|
#define G_LOG_DOMAIN "pcm"
|
||||||
|
|
||||||
|
static int lsr_converter = SRC_SINC_FASTEST;
|
||||||
|
|
||||||
static inline GQuark
|
static inline GQuark
|
||||||
libsamplerate_quark(void)
|
libsamplerate_quark(void)
|
||||||
{
|
{
|
||||||
return g_quark_from_static_string("libsamplerate");
|
return g_quark_from_static_string("libsamplerate");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
lsr_parse_converter(const char *s)
|
||||||
|
{
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
if (*s == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
char *endptr;
|
||||||
|
long l = strtol(s, &endptr, 10);
|
||||||
|
if (*endptr == 0 && src_get_name(l) != NULL) {
|
||||||
|
lsr_converter = l;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length = strlen(s);
|
||||||
|
for (int i = 0;; ++i) {
|
||||||
|
const char *name = src_get_name(i);
|
||||||
|
if (name == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (g_ascii_strncasecmp(s, name, length) == 0) {
|
||||||
|
lsr_converter = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
pcm_resample_lsr_global_init(const char *converter, GError **error_r)
|
||||||
|
{
|
||||||
|
if (!lsr_parse_converter(converter)) {
|
||||||
|
g_set_error(error_r, libsamplerate_quark(), 0,
|
||||||
|
"unknown samplerate converter '%s'", converter);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_debug("libsamplerate converter '%s'",
|
||||||
|
src_get_name(lsr_converter));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pcm_resample_lsr_deinit(struct pcm_resample_state *state)
|
pcm_resample_lsr_deinit(struct pcm_resample_state *state)
|
||||||
{
|
{
|
||||||
@@ -47,54 +94,14 @@ pcm_resample_lsr_deinit(struct pcm_resample_state *state)
|
|||||||
pcm_buffer_deinit(&state->buffer);
|
pcm_buffer_deinit(&state->buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pcm_resample_get_converter(void)
|
|
||||||
{
|
|
||||||
const char *conf = config_get_string(CONF_SAMPLERATE_CONVERTER, NULL);
|
|
||||||
long convalgo;
|
|
||||||
char *test;
|
|
||||||
const char *test2;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (!conf) {
|
|
||||||
convalgo = SRC_SINC_FASTEST;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
convalgo = strtol(conf, &test, 10);
|
|
||||||
if (*test == '\0' && src_get_name(convalgo))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
len = strlen(conf);
|
|
||||||
for (convalgo = 0 ; ; convalgo++) {
|
|
||||||
test2 = src_get_name(convalgo);
|
|
||||||
if (!test2) {
|
|
||||||
convalgo = SRC_SINC_FASTEST;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (g_ascii_strncasecmp(test2, conf, len) == 0)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_warning("unknown samplerate converter \"%s\"", conf);
|
|
||||||
out:
|
|
||||||
g_debug("selecting samplerate converter \"%s\"",
|
|
||||||
src_get_name(convalgo));
|
|
||||||
|
|
||||||
return convalgo;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
pcm_resample_set(struct pcm_resample_state *state,
|
pcm_resample_set(struct pcm_resample_state *state,
|
||||||
uint8_t channels, unsigned src_rate, unsigned dest_rate,
|
uint8_t channels, unsigned src_rate, unsigned dest_rate,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
static int convalgo = -1;
|
|
||||||
int error;
|
int error;
|
||||||
SRC_DATA *data = &state->data;
|
SRC_DATA *data = &state->data;
|
||||||
|
|
||||||
if (convalgo < 0)
|
|
||||||
convalgo = pcm_resample_get_converter();
|
|
||||||
|
|
||||||
/* (re)set the state/ratio if the in or out format changed */
|
/* (re)set the state/ratio if the in or out format changed */
|
||||||
if (channels == state->prev.channels &&
|
if (channels == state->prev.channels &&
|
||||||
src_rate == state->prev.src_rate &&
|
src_rate == state->prev.src_rate &&
|
||||||
@@ -109,7 +116,7 @@ pcm_resample_set(struct pcm_resample_state *state,
|
|||||||
if (state->state)
|
if (state->state)
|
||||||
state->state = src_delete(state->state);
|
state->state = src_delete(state->state);
|
||||||
|
|
||||||
state->state = src_new(convalgo, channels, &error);
|
state->state = src_new(lsr_converter, channels, &error);
|
||||||
if (!state->state) {
|
if (!state->state) {
|
||||||
g_set_error(error_r, libsamplerate_quark(), state->error,
|
g_set_error(error_r, libsamplerate_quark(), state->error,
|
||||||
"libsamplerate initialization has failed: %s",
|
"libsamplerate initialization has failed: %s",
|
||||||
|
Reference in New Issue
Block a user