mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-31 22:25:35 -04:00
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.
This commit is contained in:
parent
a0dcf5f8d1
commit
7eff603576
8 changed files with 284 additions and 313 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
#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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue