{ C(reminder_interval), &type_integer, validate_positive },
{ C(remote_userman), &type_boolean, validate_any },
{ C2(restrict, restrictions), &type_restrict, validate_any },
+ { C(rtp_delay_threshold), &type_integer, validate_positive },
{ C(sample_format), &type_sample_format, validate_sample_format },
{ C(scratch), &type_string_accum, validate_isreg },
{ C(sendmail), &type_string, validate_isabspath },
/** @brief Source address for network audio transmission */
struct stringlist broadcast_from;
+ /** @brief RTP delay threshold */
+ long rtp_delay_threshold;
+
/** @brief TTL for multicast packets */
long multicast_ttl;
#include "mem.h"
#include "log.h"
#include "uaudio.h"
+#include "configuration.h"
/** @brief The current PCM handle */
static snd_pcm_t *alsa_pcm;
*right = to_percent(r);
}
+static void alsa_configure(void) {
+ uaudio_set("device", config->device);
+ uaudio_set("mixer-control", config->mixer);
+ uaudio_set("mixer-channel", config->channel);
+}
+
const struct uaudio uaudio_alsa = {
.name = "alsa",
.options = alsa_options,
.close_mixer = alsa_close_mixer,
.get_volume = alsa_get_volume,
.set_volume = alsa_set_volume,
+ .configure = alsa_configure
};
#endif
#include "mem.h"
#include "wstat.h"
#include "uaudio.h"
+#include "configuration.h"
/** @brief Pipe to subprocess */
static int command_fd;
uaudio_thread_deactivate();
}
+static void command_configure(void) {
+ uaudio_set("command", config->speaker_command);
+}
+
const struct uaudio uaudio_command = {
.name = "command",
.options = command_options,
.start = command_start,
.stop = command_stop,
.activate = command_activate,
- .deactivate = command_deactivate
+ .deactivate = command_deactivate,
+ .configure = command_configure,
};
/*
#include "mem.h"
#include "log.h"
#include "syscalls.h"
+#include "configuration.h"
/** @brief Callback to request sample data */
static uaudio_callback *coreaudio_callback;
coreaudio_fatal(status, "AudioDeviceStop");
}
+static void coreaudio_configure(void) {
+ uaudio_set("device", config->device);
+}
+
const struct uaudio uaudio_coreaudio = {
.name = "coreaudio",
.options = coreaudio_options,
.start = coreaudio_start,
.stop = coreaudio_stop,
.activate = coreaudio_activate,
- .deactivate = coreaudio_deactivate
+ .deactivate = coreaudio_deactivate,
+ .configure = coreaudio_configure,
};
#endif
#include "mem.h"
#include "log.h"
#include "uaudio.h"
+#include "configuration.h"
#ifndef AFMT_U16_NE
# if BYTE_ORDER == BIG_ENDIAN
}
}
+static void oss_configure(void) {
+ uaudio_set("device", config->device);
+ uaudio_set("mixer-device", config->mixer);
+ uaudio_set("mixer-channel", config->channel);
+}
+
const struct uaudio uaudio_oss = {
.name = "oss",
.options = oss_options,
.close_mixer = oss_close_mixer,
.get_volume = oss_get_volume,
.set_volume = oss_set_volume,
+ .configure = oss_configure,
};
#endif
#include "addr.h"
#include "ifreq.h"
#include "timeval.h"
+#include "configuration.h"
/** @brief Bytes to send per network packet
*
uaudio_thread_deactivate();
}
+static void rtp_configure(void) {
+ char buffer[64];
+
+ uaudio_set("rtp-destination", config->broadcast.s[0]);
+ uaudio_set("rtp-destination-port", config->broadcast.s[1]);
+ if(config->broadcast_from.n) {
+ uaudio_set("rtp-source", config->broadcast_from.s[0]);
+ uaudio_set("rtp-source-port", config->broadcast_from.s[0]);
+ } else {
+ uaudio_set("rtp-source", NULL);
+ uaudio_set("rtp-source-port", NULL);
+ }
+ snprintf(buffer, sizeof buffer, "%ld", config->multicast_ttl);
+ uaudio_set("multicast-ttl", buffer);
+ uaudio_set("multicast-loop", config->multicast_loop ? "yes" : "no");
+ snprintf(buffer, sizeof buffer, "%ld", config->rtp_delay_threshold);
+ uaudio_set("delay-threshold", buffer);
+}
+
const struct uaudio uaudio_rtp = {
.name = "rtp",
.options = rtp_options,
.start = rtp_start,
.stop = rtp_stop,
.activate = rtp_activate,
- .deactivate = rtp_deactivate
+ .deactivate = rtp_deactivate,
+ .configure = rtp_configure,
};
/*
/** @brief Set a uaudio option */
void uaudio_set(const char *name, const char *value) {
+ if(!value) {
+ if(uaudio_options)
+ hash_remove(uaudio_options, name);
+ return;
+ }
if(!uaudio_options)
uaudio_options = hash_new(sizeof(char *));
value = xstrdup(value);
/** @brief Get a uaudio option */
char *uaudio_get(const char *name, const char *default_value) {
- const char *value = (uaudio_options ?
- *(char **)hash_find(uaudio_options, name)
- : default_value);
- return value ? xstrdup(value) : NULL;
+ if(!uaudio_options)
+ return default_value ? xstrdup(default_value) : 0;
+ char **valuep = hash_find(uaudio_options, name);
+ if(!valuep)
+ return default_value ? xstrdup(default_value) : 0;
+ return xstrdup(*valuep);
}
/** @brief Set sample format
* 0 is silent and 100 is maximum volume.
*/
void (*set_volume)(int *left, int *right);
+
+ /** @brief Set configuration */
+ void (*configure)(void);
};
/* TODO other parameters! */
backend = uaudio_find(config->api);
/* backend-specific initialization */
+ if(backend->configure)
+ backend->configure();
backend->start(speaker_callback, NULL);
/* create the socket directory */
byte_xasprintf(&dir, "%s/speaker", config->home);
/* We only allow for upgrade at startup */
trackdb_open(TRACKDB_CAN_UPGRADE);
api = uaudio_find(config->api);
+ if(api->configure)
+ api->configure();
if(api->open_mixer)
api->open_mixer();
if(need_another_rescan)