]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Support multi-card/device for direct plugins
authorTakashi Iwai <tiwai@suse.de>
Mon, 16 Jan 2006 13:15:32 +0000 (13:15 +0000)
committerTakashi Iwai <tiwai@suse.de>
Mon, 16 Jan 2006 13:15:32 +0000 (13:15 +0000)
- 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
src/conf/pcm/dmix.conf
src/conf/pcm/dsnoop.conf
src/pcm/pcm_direct.c
src/pcm/pcm_direct.h
src/pcm/pcm_dmix.c
src/pcm/pcm_dshare.c
src/pcm/pcm_dsnoop.c

index 73e440d40034bac3847b648444faf50f720ebdab..25e06d2353a060dd13d3444d619fdd9005b724bd 100644 (file)
@@ -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
index b505be2c6ab05cc8519b669634a3af8218a20e48..32700f240491e7318ee2fd45f42e6b7531be4601 100644 (file)
@@ -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
index 1eba61e6fd667cf209a849beaa3b643a79c75e0c..dfdcf58de356c57460969a95297a9d4738129a3a 100644 (file)
@@ -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
index a3eedc25e9bf45398e67312263d7feaa18fc7062..113930e172a6cd7e16727021dcfab6386b8d84d9 100644 (file)
@@ -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;
+}
index 6588fa5601909740faaae5b1903cfd0028094a53..6a8bf791df07a180fb1d8521530cedf2168a1b38 100644 (file)
@@ -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);
index c171f8e1b4d9cfd5384765ddd0aad24b3b724b06..4f61a368e84e3110ba218b2d37147c2d9e9bfd98 100644 (file)
@@ -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, &params.format,
                                 SND_PCM_HW_PARAM_RATE, 0, &params.rate,
                                 SND_PCM_HW_PARAM_CHANNELS, 0, &params.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, &params, 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,
+                               &params, dopen.bindings, dopen.slowptr,
+                               root, sconf, stream, mode);
        if (err < 0)
                snd_config_delete(sconf);
        return err;
index c732b1756c8b03b9be6402769d2d66cc4bbb41ff..c7cd9922d94503fa22c40bb34b171c32db2865a7 100644 (file)
@@ -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, &params.format,
                                 SND_PCM_HW_PARAM_RATE, 0, &params.rate,
                                 SND_PCM_HW_PARAM_CHANNELS, 0, &params.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, &params, 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,
+                                 &params, dopen.bindings, dopen.slowptr,
+                                 root, sconf, stream, mode);
        if (err < 0)
                snd_config_delete(sconf);
        return err;
index 3e64889b580df273c0addd34ff7737fe0e65d0da..6fe1bd52cab95ecf99c1d8c9c2255a6a7dc6307f 100644 (file)
@@ -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, &params.format,
                                 SND_PCM_HW_PARAM_RATE, 0, &params.rate,
                                 SND_PCM_HW_PARAM_CHANNELS, 0, &params.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, &params, 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,
+                                 &params, dopen.bindings, dopen.slowptr,
+                                 root, sconf, stream, mode);
        if (err < 0)
                snd_config_delete(sconf);
        return err;