[outputs/conf] New multiple 'alsa' sections split from 'audio'

This commit is contained in:
whatdoineed2do/Ray 2019-12-22 19:08:43 +00:00 committed by ejurgensen
parent 8248d2fe9f
commit 0cb4e0b862
4 changed files with 95 additions and 13 deletions

View File

@ -274,3 +274,29 @@ audio {
mixer_device="hw:1"
}
```
## Multiple devices
If your machine has multiple physical devices like our Raspberry Pi example above (the DAC hat and the onboard headphone jack), we can make all these devices available to `forked-daapd` using seperate `alsa { .. }` sections.
NB: When introducing `alsa { .. }` section(s) the ALSA specific configuration in the `audio { .. }` section will be ignored.
For example:
```
audio {
type = "alsa"
}
alsa "dac" {
card="dac"
mixer="Analogue"
mixer_device="hw:1"
}
alsa "headphones" {
card = "hw:0,0"
mixer = "PCM"
mixer_device = "hw:0"
}
```

View File

@ -216,6 +216,8 @@ audio {
# socket.
# server = ""
# ALSA settings can be definied in their own 'alsa { }' sections for
# multiple devices
# Audio PCM device name for local audio output - ALSA only
# card = "default"
@ -246,6 +248,25 @@ audio {
# adjust_period_seconds = 100
}
# ALSA device settings
# Multiple sections can be defined for multiple ALSA devices on a host (i.e. a
# RPi with onboard headphones and DAC hat). ALSA may see these devices as hw:0
# and hw:1 via 'aplay -l' (see README_ALSA)
#
# Overrides ALSA settings in 'audio' section
#alsa "alsa default" {
# Audio PCM device name for local audio output
# card = "default"
# Mixer channel to use for volume control
# If not set, PCM will be used if available, otherwise Master.
# mixer = ""
# Mixer device to use for volume control
# If not set, the value for "card" will be used.
# mixer_device = ""
#}
# Pipe output
# Allows forked-daapd to output audio data to a named pipe
#fifo {

View File

@ -124,6 +124,17 @@ static cfg_opt_t sec_audio[] =
CFG_END()
};
/* local ALSA audio section structure */
static cfg_opt_t sec_alsa[] =
{
CFG_STR("card", "default", CFGF_NONE),
CFG_STR("mixer", NULL, CFGF_NONE),
CFG_STR("mixer_device", NULL, CFGF_NONE),
CFG_INT("offset_ms", 0, CFGF_NONE),
CFG_END()
};
/* AirPlay/ApEx device section structure */
static cfg_opt_t sec_airplay[] =
{
@ -201,6 +212,7 @@ static cfg_opt_t toplvl_cfg[] =
CFG_SEC("general", sec_general, CFGF_NONE),
CFG_SEC("library", sec_library, CFGF_NONE),
CFG_SEC("audio", sec_audio, CFGF_NONE),
CFG_SEC("alsa", sec_alsa, CFGF_MULTI | CFGF_TITLE),
CFG_SEC("airplay", sec_airplay, CFGF_MULTI | CFGF_TITLE),
CFG_SEC("chromecast", sec_chromecast, CFGF_MULTI | CFGF_TITLE),
CFG_SEC("fifo", sec_fifo, CFGF_NONE),

View File

@ -974,10 +974,12 @@ alsa_session_make(struct output_device *device, int callback_id)
CHECK_NULL(L_LAUDIO, as = calloc(1, sizeof(struct alsa_session)));
DPRINTF(E_DBG, L_LAUDIO, "alsa dev=%s type=%s callback=%d\n", device->name, device->type_name, callback_id);
as->device_id = device->id;
as->callback_id = callback_id;
cfg_audio = cfg_getsec(cfg, "audio");
cfg_audio = cfg_size(cfg, "alsa") == 0 ? cfg_getsec(cfg, "audio") : cfg_gettsec(cfg, "alsa", device->name);
as->devname = cfg_getstr(cfg_audio, "card");
as->mixer_name = cfg_getstr(cfg_audio, "mixer");
@ -1175,12 +1177,31 @@ alsa_write(struct output_buffer *obuf)
}
}
static void
alsa_device_add(cfg_t* cfg_audio, int id, const char* devname)
{
struct output_device *device;
CHECK_NULL(L_LAUDIO, device = calloc(1, sizeof(struct output_device)));
device->id = id;
device->name = strdup(devname);
device->type = OUTPUT_TYPE_ALSA;
device->type_name = outputs_name(device->type);
device->has_video = 0;
DPRINTF(E_INFO, L_LAUDIO, "Adding ALSA device '%s' with name '%s'\n", cfg_getstr(cfg_audio, "card"), device->name);
player_device_add(device);
}
static int
alsa_init(void)
{
struct output_device *device;
cfg_t *cfg_audio;
cfg_t *cfg_alsasec;
const char *type;
int i;
int alsa_cfg_secn;
// Is ALSA enabled in config?
cfg_audio = cfg_getsec(cfg, "audio");
@ -1191,17 +1212,19 @@ alsa_init(void)
alsa_sync_disable = cfg_getbool(cfg_audio, "sync_disable");
alsa_latency_history_size = cfg_getint(cfg_audio, "adjust_period_seconds");
CHECK_NULL(L_LAUDIO, device = calloc(1, sizeof(struct output_device)));
device->id = 0;
device->name = strdup(cfg_getstr(cfg_audio, "nickname"));
device->type = OUTPUT_TYPE_ALSA;
device->type_name = outputs_name(device->type);
device->has_video = 0;
DPRINTF(E_INFO, L_LAUDIO, "Adding ALSA device '%s' with name '%s'\n", cfg_getstr(cfg_audio, "card"), device->name);
player_device_add(device);
alsa_cfg_secn = cfg_size(cfg, "alsa");
if (alsa_cfg_secn == 0)
{
alsa_device_add(cfg_audio, 0, cfg_getstr(cfg_audio, "nickname"));
}
else
{
for (i = 0; i < alsa_cfg_secn; ++i)
{
cfg_alsasec = cfg_getnsec(cfg, "alsa", i);
alsa_device_add(cfg_alsasec, i, cfg_alsasec->title);
}
}
snd_lib_error_set_handler(logger_alsa);