mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-26 22:23:17 -05:00
[outputs/conf] New multiple 'alsa' sections split from 'audio'
This commit is contained in:
parent
8248d2fe9f
commit
0cb4e0b862
@ -274,3 +274,29 @@ audio {
|
|||||||
mixer_device="hw:1"
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
@ -216,6 +216,8 @@ audio {
|
|||||||
# socket.
|
# socket.
|
||||||
# server = ""
|
# server = ""
|
||||||
|
|
||||||
|
# ALSA settings can be definied in their own 'alsa { }' sections for
|
||||||
|
# multiple devices
|
||||||
# Audio PCM device name for local audio output - ALSA only
|
# Audio PCM device name for local audio output - ALSA only
|
||||||
# card = "default"
|
# card = "default"
|
||||||
|
|
||||||
@ -246,6 +248,25 @@ audio {
|
|||||||
# adjust_period_seconds = 100
|
# 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
|
# Pipe output
|
||||||
# Allows forked-daapd to output audio data to a named pipe
|
# Allows forked-daapd to output audio data to a named pipe
|
||||||
#fifo {
|
#fifo {
|
||||||
|
@ -124,6 +124,17 @@ static cfg_opt_t sec_audio[] =
|
|||||||
CFG_END()
|
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 */
|
/* AirPlay/ApEx device section structure */
|
||||||
static cfg_opt_t sec_airplay[] =
|
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("general", sec_general, CFGF_NONE),
|
||||||
CFG_SEC("library", sec_library, CFGF_NONE),
|
CFG_SEC("library", sec_library, CFGF_NONE),
|
||||||
CFG_SEC("audio", sec_audio, 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("airplay", sec_airplay, CFGF_MULTI | CFGF_TITLE),
|
||||||
CFG_SEC("chromecast", sec_chromecast, CFGF_MULTI | CFGF_TITLE),
|
CFG_SEC("chromecast", sec_chromecast, CFGF_MULTI | CFGF_TITLE),
|
||||||
CFG_SEC("fifo", sec_fifo, CFGF_NONE),
|
CFG_SEC("fifo", sec_fifo, CFGF_NONE),
|
||||||
|
@ -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)));
|
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->device_id = device->id;
|
||||||
as->callback_id = callback_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->devname = cfg_getstr(cfg_audio, "card");
|
||||||
as->mixer_name = cfg_getstr(cfg_audio, "mixer");
|
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
|
static int
|
||||||
alsa_init(void)
|
alsa_init(void)
|
||||||
{
|
{
|
||||||
struct output_device *device;
|
|
||||||
cfg_t *cfg_audio;
|
cfg_t *cfg_audio;
|
||||||
|
cfg_t *cfg_alsasec;
|
||||||
const char *type;
|
const char *type;
|
||||||
|
int i;
|
||||||
|
int alsa_cfg_secn;
|
||||||
|
|
||||||
// Is ALSA enabled in config?
|
// Is ALSA enabled in config?
|
||||||
cfg_audio = cfg_getsec(cfg, "audio");
|
cfg_audio = cfg_getsec(cfg, "audio");
|
||||||
@ -1191,17 +1212,19 @@ alsa_init(void)
|
|||||||
alsa_sync_disable = cfg_getbool(cfg_audio, "sync_disable");
|
alsa_sync_disable = cfg_getbool(cfg_audio, "sync_disable");
|
||||||
alsa_latency_history_size = cfg_getint(cfg_audio, "adjust_period_seconds");
|
alsa_latency_history_size = cfg_getint(cfg_audio, "adjust_period_seconds");
|
||||||
|
|
||||||
CHECK_NULL(L_LAUDIO, device = calloc(1, sizeof(struct output_device)));
|
alsa_cfg_secn = cfg_size(cfg, "alsa");
|
||||||
|
if (alsa_cfg_secn == 0)
|
||||||
device->id = 0;
|
{
|
||||||
device->name = strdup(cfg_getstr(cfg_audio, "nickname"));
|
alsa_device_add(cfg_audio, 0, cfg_getstr(cfg_audio, "nickname"));
|
||||||
device->type = OUTPUT_TYPE_ALSA;
|
}
|
||||||
device->type_name = outputs_name(device->type);
|
else
|
||||||
device->has_video = 0;
|
{
|
||||||
|
for (i = 0; i < alsa_cfg_secn; ++i)
|
||||||
DPRINTF(E_INFO, L_LAUDIO, "Adding ALSA device '%s' with name '%s'\n", cfg_getstr(cfg_audio, "card"), device->name);
|
{
|
||||||
|
cfg_alsasec = cfg_getnsec(cfg, "alsa", i);
|
||||||
player_device_add(device);
|
alsa_device_add(cfg_alsasec, i, cfg_alsasec->title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
snd_lib_error_set_handler(logger_alsa);
|
snd_lib_error_set_handler(logger_alsa);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user