From 7eff6035766756abba8816cda7b111b7babec6f0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 16 Jan 2006 13:15:32 +0000 Subject: [PATCH] Support multi-card/device for direct plugins - Support multi-card/device for dmix/dsnoop/dshare plugins The unique ipc key is calculated based on card/device/sub index - Clean up and share the code among all d* plugins - Refer the defaults.pcm.* configuration The base ipc_key number, ipc_gid and ipc_perm are referred. --- src/conf/alsa.conf | 3 + src/conf/pcm/dmix.conf | 15 +++- src/conf/pcm/dsnoop.conf | 15 +++- src/pcm/pcm_direct.c | 185 +++++++++++++++++++++++++++++++++++++++ src/pcm/pcm_direct.h | 12 +++ src/pcm/pcm_dmix.c | 121 +++++-------------------- src/pcm/pcm_dshare.c | 125 +++++--------------------- src/pcm/pcm_dsnoop.c | 123 +++++--------------------- 8 files changed, 285 insertions(+), 314 deletions(-) diff --git a/src/conf/alsa.conf b/src/conf/alsa.conf index 73e440d4..25e06d23 100644 --- a/src/conf/alsa.conf +++ b/src/conf/alsa.conf @@ -54,6 +54,9 @@ defaults.pcm.card 0 defaults.pcm.device 0 defaults.pcm.subdevice -1 defaults.pcm.nonblock 1 +defaults.pcm.ipc_key 5678293 +defaults.pcm.ipc_gid audio +defaults.pcm.ipc_perm 0660 defaults.pcm.front.card defaults.pcm.card defaults.pcm.front.device defaults.pcm.device defaults.pcm.rear.card defaults.pcm.card diff --git a/src/conf/pcm/dmix.conf b/src/conf/pcm/dmix.conf index b505be2c..32700f24 100644 --- a/src/conf/pcm/dmix.conf +++ b/src/conf/pcm/dmix.conf @@ -25,9 +25,18 @@ pcm.!dmix { default 48000 } type dmix - ipc_key 5678293 - ipc_gid audio - ipc_perm 0660 + ipc_key { + @func refer + name defaults.pcm.ipc_key + } + ipc_gid { + @func refer + name defaults.pcm.ipc_gid + } + ipc_perm { + @func refer + name defaults.pcm.ipc_perm + } slave { pcm { type hw diff --git a/src/conf/pcm/dsnoop.conf b/src/conf/pcm/dsnoop.conf index 1eba61e6..dfdcf58d 100644 --- a/src/conf/pcm/dsnoop.conf +++ b/src/conf/pcm/dsnoop.conf @@ -25,9 +25,18 @@ pcm.!dsnoop { default 48000 } type dsnoop - ipc_key 5778293 - ipc_gid audio - ipc_perm 0660 + ipc_key { + @func refer + name defaults.pcm.ipc_key + } + ipc_gid { + @func refer + name defaults.pcm.ipc_gid + } + ipc_perm { + @func refer + name defaults.pcm.ipc_perm + } slave { pcm { type hw diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c index a3eedc25..113930e1 100644 --- a/src/pcm/pcm_direct.c +++ b/src/pcm/pcm_direct.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -1254,3 +1256,186 @@ int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, snd_config_t *cfg) dmix->channels = count; return 0; } + +/* + * parse slave config and calculate the ipc_key offset + */ +int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *sconf, int direction) +{ + snd_config_iterator_t i, next; + int err; + long card = 0, device = 0, subdevice = 0; + + snd_config_for_each(i, next, sconf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id, *str; + if (snd_config_get_id(n, &id) < 0) + continue; + if (strcmp(id, "type") == 0) { + err = snd_config_get_string(n, &str); + if (err < 0) { + SNDERR("Invalid value for PCM type definition\n"); + return -EINVAL; + } + if (strcmp(str, "hw")) { + SNDERR("Invalid type '%s' for slave PCM\n", str); + return -EINVAL; + } + continue; + } + if (strcmp(id, "card") == 0) { + err = snd_config_get_integer(n, &card); + if (err < 0) { + err = snd_config_get_string(n, &str); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return -EINVAL; + } + card = snd_card_get_index(str); + if (card < 0) { + SNDERR("Invalid value for %s", id); + return card; + } + } + continue; + } + if (strcmp(id, "device") == 0) { + err = snd_config_get_integer(n, &device); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + continue; + } + if (strcmp(id, "subdevice") == 0) { + err = snd_config_get_integer(n, &subdevice); + if (err < 0) { + SNDERR("Invalid type for %s", id); + return err; + } + continue; + } + } + if (card < 0) + card = 0; + if (device < 0) + device = 0; + if (subdevice < 0) + subdevice = 0; + return direction + (card << 1) + (device << 4) + (subdevice << 8); +} + + +int snd_pcm_direct_parse_open_conf(snd_config_t *conf, struct snd_pcm_direct_open_conf *rec) +{ + snd_config_iterator_t i, next; + int ipc_key_add_uid = 0; + int err; + + rec->slave = NULL; + rec->bindings = NULL; + rec->ipc_key = 0; + rec->ipc_perm = 0600; + rec->ipc_gid = -1; + rec->slowptr = 0; + + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_id(n, &id) < 0) + continue; + if (snd_pcm_conf_generic_id(id)) + continue; + if (strcmp(id, "ipc_key") == 0) { + long key; + err = snd_config_get_integer(n, &key); + if (err < 0) { + SNDERR("The field ipc_key must be an integer type"); + + return err; + } + rec->ipc_key = key; + continue; + } + if (strcmp(id, "ipc_perm") == 0) { + char *perm; + char *endp; + err = snd_config_get_ascii(n, &perm); + if (err < 0) { + SNDERR("The field ipc_perm must be a valid file permission"); + return err; + } + if (isdigit(*perm) == 0) { + SNDERR("The field ipc_perm must be a valid file permission"); + free(perm); + return -EINVAL; + } + rec->ipc_perm = strtol(perm, &endp, 8); + free(perm); + continue; + } + if (strcmp(id, "ipc_gid") == 0) { + char *group; + char *endp; + err = snd_config_get_ascii(n, &group); + if (err < 0) { + SNDERR("The field ipc_gid must be a valid group"); + return err; + } + if (! *group) { + rec->ipc_gid = -1; + free(group); + continue; + } + if (isdigit(*group) == 0) { + struct group *grp = getgrnam(group); + if (grp == NULL) { + SNDERR("The field ipc_gid must be a valid group (create group %s)", group); + free(group); + return -EINVAL; + } + rec->ipc_gid = grp->gr_gid; + } else { + rec->ipc_gid = strtol(group, &endp, 10); + } + free(group); + continue; + } + if (strcmp(id, "ipc_key_add_uid") == 0) { + if ((err = snd_config_get_bool(n)) < 0) { + SNDERR("The field ipc_key_add_uid must be a boolean type"); + return err; + } + ipc_key_add_uid = err; + continue; + } + if (strcmp(id, "slave") == 0) { + rec->slave = n; + continue; + } + if (strcmp(id, "bindings") == 0) { + rec->bindings = n; + continue; + } + if (strcmp(id, "slowptr") == 0) { + err = snd_config_get_bool(n); + if (err < 0) + return err; + rec->slowptr = err; + continue; + } + SNDERR("Unknown field %s", id); + return -EINVAL; + } + if (! rec->slave) { + SNDERR("slave is not defined"); + return -EINVAL; + } + if (ipc_key_add_uid) + rec->ipc_key += getuid(); + if (!rec->ipc_key) { + SNDERR("Unique IPC key is not defined"); + return -EINVAL; + } + return 0; +} diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h index 6588fa56..6a8bf791 100644 --- a/src/pcm/pcm_direct.h +++ b/src/pcm/pcm_direct.h @@ -186,6 +186,18 @@ int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix); void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix); int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix); int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name); +int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *sconf, int direction); int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid); struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm); + +struct snd_pcm_direct_open_conf { + key_t ipc_key; + mode_t ipc_perm; + int ipc_gid; + int slowptr; + snd_config_t *slave; + snd_config_t *bindings; +}; + +int snd_pcm_direct_parse_open_conf(snd_config_t *conf, struct snd_pcm_direct_open_conf *rec); diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index c171f8e1..4f61a368 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -1078,107 +1078,17 @@ int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, snd_config_t *root, snd_config_t *conf, snd_pcm_stream_t stream, int mode) { - snd_config_iterator_t i, next; - snd_config_t *slave = NULL, *bindings = NULL, *sconf; + snd_config_t *sconf; struct slave_params params; - int bsize, psize, ipc_key_add_uid = 0, slowptr = 0; - key_t ipc_key = 0; - mode_t ipc_perm = 0600; - int ipc_gid = -1; + struct snd_pcm_direct_open_conf dopen; + int bsize, psize; + int ipc_offset; int err; - snd_config_for_each(i, next, conf) { - snd_config_t *n = snd_config_iterator_entry(i); - const char *id; - if (snd_config_get_id(n, &id) < 0) - continue; - if (snd_pcm_conf_generic_id(id)) - continue; - if (strcmp(id, "ipc_key") == 0) { - long key; - err = snd_config_get_integer(n, &key); - if (err < 0) { - SNDERR("The field ipc_key must be an integer type"); - - return err; - } - ipc_key = key; - continue; - } - if (strcmp(id, "ipc_perm") == 0) { - char *perm; - char *endp; - err = snd_config_get_ascii(n, &perm); - if (err < 0) { - SNDERR("The field ipc_perm must be a valid file permission"); - return err; - } - if (isdigit(*perm) == 0) { - SNDERR("The field ipc_perm must be a valid file permission"); - free(perm); - return -EINVAL; - } - ipc_perm = strtol(perm, &endp, 8); - free(perm); - continue; - } - if (strcmp(id, "ipc_gid") == 0) { - char *group; - char *endp; - err = snd_config_get_ascii(n, &group); - if (err < 0) { - SNDERR("The field ipc_gid must be a valid group"); - return err; - } - if (isdigit(*group) == 0) { - struct group *grp = getgrnam(group); - if (grp == NULL) { - SNDERR("The field ipc_gid must be a valid group (create group %s)", group); - free(group); - return -EINVAL; - } - ipc_gid = grp->gr_gid; - } else { - ipc_gid = strtol(group, &endp, 10); - } - free(group); - continue; - } - if (strcmp(id, "ipc_key_add_uid") == 0) { - if ((err = snd_config_get_bool(n)) < 0) { - SNDERR("The field ipc_key_add_uid must be a boolean type"); - return err; - } - ipc_key_add_uid = err; - continue; - } - if (strcmp(id, "slave") == 0) { - slave = n; - continue; - } - if (strcmp(id, "bindings") == 0) { - bindings = n; - continue; - } - if (strcmp(id, "slowptr") == 0) { - err = snd_config_get_bool(n); - if (err < 0) - return err; - slowptr = err; - continue; - } - SNDERR("Unknown field %s", id); - return -EINVAL; - } - if (!slave) { - SNDERR("slave is not defined"); - return -EINVAL; - } - if (ipc_key_add_uid) - ipc_key += getuid(); - if (!ipc_key) { - SNDERR("Unique IPC key is not defined"); - return -EINVAL; - } + + err = snd_pcm_direct_parse_open_conf(conf, &dopen); + if (err < 0) + return err; + /* the default settings, it might be invalid for some hardware */ params.format = SND_PCM_FORMAT_S16; params.rate = 48000; @@ -1188,7 +1098,7 @@ int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, bsize = psize = -1; params.periods = 3; - err = snd_pcm_slave_conf(root, slave, &sconf, 8, + err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8, SND_PCM_HW_PARAM_FORMAT, 0, ¶ms.format, SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate, SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels, @@ -1214,7 +1124,16 @@ int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, params.period_size = psize; params.buffer_size = bsize; - err = snd_pcm_dmix_open(pcmp, name, ipc_key, ipc_perm, ipc_gid, ¶ms, bindings, slowptr, root, sconf, stream, mode); + ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream); + if (ipc_offset < 0) { + snd_config_delete(sconf); + return ipc_offset; + } + dopen.ipc_key += ipc_offset; + + err = snd_pcm_dmix_open(pcmp, name, dopen.ipc_key, dopen.ipc_perm, dopen.ipc_gid, + ¶ms, dopen.bindings, dopen.slowptr, + root, sconf, stream, mode); if (err < 0) snd_config_delete(sconf); return err; diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c index c732b175..c7cd9922 100644 --- a/src/pcm/pcm_dshare.c +++ b/src/pcm/pcm_dshare.c @@ -835,110 +835,17 @@ int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, snd_config_t *root, snd_config_t *conf, snd_pcm_stream_t stream, int mode) { - snd_config_iterator_t i, next; - snd_config_t *slave = NULL, *bindings = NULL, *sconf; + snd_config_t *sconf; struct slave_params params; - int bsize, psize, ipc_key_add_uid = 0, slowptr = 0; - key_t ipc_key = 0; - mode_t ipc_perm = 0600; - int ipc_gid = -1; - + struct snd_pcm_direct_open_conf dopen; + int bsize, psize; + int ipc_offset; int err; - snd_config_for_each(i, next, conf) { - snd_config_t *n = snd_config_iterator_entry(i); - const char *id; - if (snd_config_get_id(n, &id) < 0) - continue; - if (snd_pcm_conf_generic_id(id)) - continue; - if (strcmp(id, "ipc_key") == 0) { - long key; - err = snd_config_get_integer(n, &key); - if (err < 0) { - SNDERR("The field ipc_key must be an integer type"); - return err; - } - ipc_key = key; - continue; - } - if (strcmp(id, "ipc_perm") == 0) { - char *perm; - char *endp; - err = snd_config_get_ascii(n, &perm); - if (err < 0) { - SNDERR("The field ipc_perm must be a valid file permission"); - return err; - } - if (isdigit(*perm) == 0) { - SNDERR("The field ipc_perm must be a valid file permission"); - free(perm); - return -EINVAL; - } - ipc_perm = strtol(perm, &endp, 8); - free(perm); - continue; - } - if (strcmp(id, "ipc_gid") == 0) { - char *group; - char *endp; - err = snd_config_get_ascii(n, &group); - if (err < 0) { - SNDERR("The field ipc_gid must be a valid group"); - return err; - } - if (isdigit(*group) == 0) { - struct group *grp = getgrnam(group); - if (group == NULL) { - SNDERR("The field ipc_gid must be a valid group (create group %s)", group); - free(group); - return -EINVAL; - } - ipc_gid = grp->gr_gid; - } else { - ipc_gid = strtol(group, &endp, 10); - } - free(group); - continue; - } - if (strcmp(id, "ipc_key_add_uid") == 0) { - err = snd_config_get_bool(n); - if (err < 0) { - SNDERR("The field ipc_key_add_uid must be a boolean type"); - return err; - } - ipc_key_add_uid = err; - continue; - } - if (strcmp(id, "slave") == 0) { - slave = n; - continue; - } - if (strcmp(id, "bindings") == 0) { - bindings = n; - continue; - } - if (strcmp(id, "slowptr") == 0) { - err = snd_config_get_bool(n); - if (err < 0) { - SNDERR("The field slowptr must be a boolean type"); - return err; - } - slowptr = err; - continue; - } - SNDERR("Unknown field %s", id); - return -EINVAL; - } - if (!slave) { - SNDERR("slave is not defined"); - return -EINVAL; - } - if (ipc_key_add_uid) - ipc_key += getuid(); - if (!ipc_key) { - SNDERR("Unique IPC key is not defined"); - return -EINVAL; - } + + err = snd_pcm_direct_parse_open_conf(conf, &dopen); + if (err < 0) + return err; + /* the default settings, it might be invalid for some hardware */ params.format = SND_PCM_FORMAT_S16; params.rate = 48000; @@ -947,7 +854,7 @@ int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, params.buffer_time = -1; bsize = psize = -1; params.periods = 3; - err = snd_pcm_slave_conf(root, slave, &sconf, 8, + err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8, SND_PCM_HW_PARAM_FORMAT, 0, ¶ms.format, SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate, SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels, @@ -965,7 +872,17 @@ int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, params.period_size = psize; params.buffer_size = bsize; - err = snd_pcm_dshare_open(pcmp, name, ipc_key, ipc_perm, ipc_gid, ¶ms, bindings, slowptr, root, sconf, stream, mode); + + ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream); + if (ipc_offset < 0) { + snd_config_delete(sconf); + return ipc_offset; + } + dopen.ipc_key += ipc_offset; + + err = snd_pcm_dshare_open(pcmp, name, dopen.ipc_key, dopen.ipc_perm, dopen.ipc_gid, + ¶ms, dopen.bindings, dopen.slowptr, + root, sconf, stream, mode); if (err < 0) snd_config_delete(sconf); return err; diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c index 3e64889b..6fe1bd52 100644 --- a/src/pcm/pcm_dsnoop.c +++ b/src/pcm/pcm_dsnoop.c @@ -707,110 +707,17 @@ int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, snd_config_t *root, snd_config_t *conf, snd_pcm_stream_t stream, int mode) { - snd_config_iterator_t i, next; - snd_config_t *slave = NULL, *bindings = NULL, *sconf; + snd_config_t *sconf; struct slave_params params; - int bsize, psize, ipc_key_add_uid = 0, slowptr = 0; - key_t ipc_key = 0; - mode_t ipc_perm = 0600; - int ipc_gid = -1; + struct snd_pcm_direct_open_conf dopen; + int bsize, psize; + int ipc_offset; int err; - snd_config_for_each(i, next, conf) { - snd_config_t *n = snd_config_iterator_entry(i); - const char *id; - if (snd_config_get_id(n, &id) < 0) - continue; - if (snd_pcm_conf_generic_id(id)) - continue; - if (strcmp(id, "ipc_key") == 0) { - long key; - err = snd_config_get_integer(n, &key); - if (err < 0) { - SNDERR("The field ipc_key must be an integer type"); - return err; - } - ipc_key = key; - continue; - } - if (strcmp(id, "ipc_perm") == 0) { - char *perm; - char *endp; - err = snd_config_get_ascii(n, &perm); - if (err < 0) { - SNDERR("The field ipc_perm must be a valid file permission"); - return err; - } - if (isdigit(*perm) == 0) { - SNDERR("The field ipc_perm must be a valid file permission"); - free(perm); - return -EINVAL; - } - ipc_perm = strtol(perm, &endp, 8); - free(perm); - continue; - } - if (strcmp(id, "ipc_gid") == 0) { - char *group; - char *endp; - err = snd_config_get_ascii(n, &group); - if (err < 0) { - SNDERR("The field ipc_gid must be a valid group"); - return err; - } - if (isdigit(*group) == 0) { - struct group *grp = getgrnam(group); - if (group == NULL) { - SNDERR("The field ipc_gid must be a valid group (create group %s)", group); - free(group); - return -EINVAL; - } - ipc_gid = grp->gr_gid; - } else { - ipc_gid = strtol(group, &endp, 10); - } - free(group); - continue; - } - if (strcmp(id, "ipc_key_add_uid") == 0) { - err = snd_config_get_bool(n); - if (err < 0) { - SNDERR("The field ipc_key_add_uid must be a boolean type"); - return err; - } - ipc_key_add_uid = err; - continue; - } - if (strcmp(id, "slave") == 0) { - slave = n; - continue; - } - if (strcmp(id, "bindings") == 0) { - bindings = n; - continue; - } - if (strcmp(id, "slowptr") == 0) { - err = snd_config_get_bool(n); - if (err < 0) { - SNDERR("The field slowptr must be a boolean type"); - return err; - } - slowptr = err; - continue; - } - SNDERR("Unknown field %s", id); - return -EINVAL; - } - if (!slave) { - SNDERR("slave is not defined"); - return -EINVAL; - } - if (ipc_key_add_uid) - ipc_key += getuid(); - if (!ipc_key) { - SNDERR("Unique IPC key is not defined"); - return -EINVAL; - } + err = snd_pcm_direct_parse_open_conf(conf, &dopen); + if (err < 0) + return err; + /* the default settings, it might be invalid for some hardware */ params.format = SND_PCM_FORMAT_S16; params.rate = 48000; @@ -819,7 +726,7 @@ int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, params.buffer_time = -1; bsize = psize = -1; params.periods = 3; - err = snd_pcm_slave_conf(root, slave, &sconf, 8, + err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8, SND_PCM_HW_PARAM_FORMAT, 0, ¶ms.format, SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate, SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels, @@ -837,7 +744,17 @@ int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, params.period_size = psize; params.buffer_size = bsize; - err = snd_pcm_dsnoop_open(pcmp, name, ipc_key, ipc_perm, ipc_gid, ¶ms, bindings, slowptr, root, sconf, stream, mode); + + ipc_offset = snd_pcm_direct_get_slave_ipc_offset(sconf, stream); + if (ipc_offset < 0) { + snd_config_delete(sconf); + return ipc_offset; + } + dopen.ipc_key += ipc_offset; + + err = snd_pcm_dsnoop_open(pcmp, name, dopen.ipc_key, dopen.ipc_perm, dopen.ipc_gid, + ¶ms, dopen.bindings, dopen.slowptr, + root, sconf, stream, mode); if (err < 0) snd_config_delete(sconf); return err; -- 2.47.1