-SRCS := shairport.c rtsp.c mdns.c common.c rtp.c player.c alac.c $(wildcard audio_*.c)
+SRCS := shairport.c rtsp.c mdns.c audio.c common.c rtp.c player.c alac.c $(wildcard audio_*.c)
LIBS := -lcrypto -lm -lao -lpthread
shairport: $(SRCS)
- gcc -ggdb -Wall $(SRCS) $(LIBS) -o shairport
+ gcc -ggdb -Wall -Wno-unused-value $(SRCS) $(LIBS) -o shairport
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include "audio.h"
+#include "config.h"
+
+#ifdef CONFIG_AO
+extern audio_output audio_ao;
+#endif
+extern audio_output audio_dummy;
+
+static audio_output *outputs[] = {
+#ifdef CONFIG_AO
+ &audio_ao,
+#endif
+ &audio_dummy,
+ NULL
+};
+
+
+audio_output *audio_get_output(char *name) {
+ audio_output **out;
+
+ // default to the first
+ if (!name)
+ return outputs[0];
+
+ for (out=outputs; *out; out++)
+ if (!strcasecmp(name, (*out)->name))
+ return *out;
+
+ return NULL;
+}
+
+void audio_ls_outputs(void) {
+ audio_output **out;
+
+ printf("Available audio outputs:\n");
+ for (out=outputs; *out; out++)
+ printf(" %s%s\n", (*out)->name, out==outputs ? " (default)" : "");
+}
#define _AUDIO_H
typedef struct {
+ void (*help)(void);
+ char *name;
+
// start of program
int (*init)(int argc, char **argv);
// at end of program
// may be NULL, in which case soft volume is applied
void (*volume)(double vol);
-} audio_ops;
+} audio_output;
-extern audio_ops audio_dummy;
-extern audio_ops audio_ao;
+audio_output *audio_get_output(char *name);
+void audio_ls_outputs(void);
#endif //_AUDIO_H
ao_device *dev = NULL;
+static void help(void) {
+ printf(" -d driver set the output driver\n"
+ " -o name=value set an arbitrary ao option\n"
+ " -i id shorthand for -o id=<id>\n"
+ " -n name shorthand for -o dev=<name> -o dsp=<name>\n"
+ );
+}
+
static int init(int argc, char **argv) {
printf("ao: init\n");
ao_initialize();
static void stop(void) {
}
-audio_ops audio_ao = {
+audio_output audio_ao = {
+ .name = "ao",
+ .help = &help,
.init = &init,
.deinit = &deinit,
.start = &start,
int Fs;
long long starttime, samples_played;
-static int dummy_init(int argc, char **argv) {
+static int init(int argc, char **argv) {
return 0;
}
-static void dummy_deinit(void) {
+static void deinit(void) {
}
-static void dummy_start(int sample_rate) {
+static void start(int sample_rate) {
Fs = sample_rate;
starttime = 0;
samples_played = 0;
printf("dummy audio output started at Fs=%d Hz\n", sample_rate);
}
-static void dummy_play(short buf[], int samples) {
+static void play(short buf[], int samples) {
struct timeval tv;
// this is all a bit expensive but it's long-term stable.
usleep(finishtime - nowtime);
}
-static void dummy_stop(void) {
+static void stop(void) {
printf("dummy audio stopped\n");
}
-audio_ops audio_dummy = {
- .init = &dummy_init,
- .deinit = &dummy_deinit,
- .start = &dummy_start,
- .stop = &dummy_stop,
- .play = &dummy_play,
+static void help(void) {
+ printf("There are no options for dummy audio.\n");
+}
+
+audio_output audio_dummy = {
+ .name = "dummy",
+ .help = &help,
+ .init = &init,
+ .deinit = &deinit,
+ .start = &start,
+ .stop = &stop,
+ .play = &play,
.volume = NULL
};
char *apname;
char hw_addr[6];
int port;
- audio_ops *output;
+ char *output_name;
+ audio_output *output;
int buffer_start_fill;
} shairport_cfg;
--- /dev/null
+#define CONFIG_AO
config.port = 9000;
config.apname = "hellothere";
- config.output = &audio_dummy;
- //config.output = &audio_ao;
+ config.output = audio_get_output(config.output_name);
+ if (!config.output) {
+ audio_ls_outputs();
+ die("Invalid audio output specified!\n");
+ }
// mask off all signals before creating threads.
// this way we control which thread gets which signals.