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
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
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
#include <signal.h>
#include <string.h>
#include <fcntl.h>
+#include <ctype.h>
+#include <grp.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/poll.h>
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;
+}
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);
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;
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,
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;
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;
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,
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;
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;
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,
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;