OSDN Git Service

Major cleaning to hw_params mechanism for plugins
authorAbramo Bagnara <abramo@alsa-project.org>
Thu, 18 Jan 2001 18:20:31 +0000 (18:20 +0000)
committerAbramo Bagnara <abramo@alsa-project.org>
Thu, 18 Jan 2001 18:20:31 +0000 (18:20 +0000)
17 files changed:
src/pcm/interval.c
src/pcm/pcm_adpcm.c
src/pcm/pcm_alaw.c
src/pcm/pcm_copy.c
src/pcm/pcm_linear.c
src/pcm/pcm_local.h
src/pcm/pcm_mulaw.c
src/pcm/pcm_multi.c
src/pcm/pcm_null.c
src/pcm/pcm_params.c
src/pcm/pcm_plug.c
src/pcm/pcm_plugin.c
src/pcm/pcm_plugin.h
src/pcm/pcm_rate.c
src/pcm/pcm_route.c
src/pcm/pcm_share.c
src/pcm/pcm_shm.c

index fb39af3..c7967bc 100644 (file)
@@ -38,19 +38,28 @@ static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem)
 static inline unsigned int div32(unsigned int a, unsigned int b, 
                                 unsigned int *r)
 {
+       if (b == 0) {
+               *r = 0;
+               return UINT_MAX;
+       }
        *r = a % b;
        return a / b;
 }
 
 static inline unsigned int div_down(unsigned int a, unsigned int b)
 {
+       if (b == 0)
+               return UINT_MAX;
        return a / b;
 }
 
 static inline unsigned int div_up(unsigned int a, unsigned int b)
 {
        unsigned int r;
-       unsigned int q = div32(a, b, &r);
+       unsigned int q;
+       if (b == 0)
+               return UINT_MAX;
+       q = div32(a, b, &r);
        if (r)
                ++q;
        return q;
@@ -83,6 +92,11 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b,
                                    unsigned int c, unsigned int *r)
 {
        u_int64_t n = (u_int64_t) a * b;
+       if (c == 0) {
+               assert(n > 0);
+               *r = 0;
+               return UINT_MAX;
+       }
        div64_32(&n, c, r);
        if (n >= UINT_MAX) {
                *r = 0;
@@ -359,7 +373,7 @@ void interval_print(const interval_t *i, snd_output_t *out)
        else if (i->min == 0 && i->openmin == 0 && 
                 i->max == UINT_MAX && i->openmax == 0)
                snd_output_printf(out, "ALL");
-       else if (interval_single(i))
+       else if (interval_single(i) && i->integer)
                snd_output_printf(out, "%u", interval_value(i));
        else
                snd_output_printf(out, "%c%u %u%c",
index 0e56a85..6928b67 100644 (file)
@@ -329,103 +329,109 @@ static int snd_pcm_adpcm_close(snd_pcm_t *pcm)
        return 0;
 }
 
-static int snd_pcm_adpcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+static int snd_pcm_adpcm_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_adpcm_t *adpcm = pcm->private;
-       snd_pcm_t *slave = adpcm->plug.slave;
        int err;
-       unsigned int cmask, lcmask;
-       snd_pcm_hw_params_t sparams;
        mask_t *access_mask = alloca(mask_sizeof());
-       mask_t *saccess_mask = alloca(mask_sizeof());
        mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-       cmask = params->cmask;
-       params->cmask = 0;
        err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
-                                     access_mask);
+                                    access_mask);
        if (err < 0)
                return err;
        if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
                mask_t *format_mask = alloca(mask_sizeof());
                mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
-               err = _snd_pcm_hw_param_mask(params,
-                                             SND_PCM_HW_PARAM_FORMAT,
-                                             format_mask);
-               if (err < 0)
-                       return err;
+               err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT,
+                                            format_mask);
        } else {
                err = _snd_pcm_hw_param_set(params,
                                            SND_PCM_HW_PARAM_FORMAT,
                                            SND_PCM_FORMAT_IMA_ADPCM, 0);
-               if (err < 0)
-                       return err;
        }
-       err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
-                                    SND_PCM_SUBFORMAT_STD, 0);
        if (err < 0)
                return err;
-       lcmask = params->cmask;
-       params->cmask |= cmask;
-
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                               saccess_mask);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
-                             adpcm->sformat, 0);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
-                              SND_PCM_SUBFORMAT_STD, 0);
-       err = snd_pcm_hw_refine2(params, &sparams,
-                                snd_pcm_generic_hw_link, slave,
-                                SND_PCM_HW_PARBIT_CHANNELS |
-                                SND_PCM_HW_PARBIT_RATE |
-                                SND_PCM_HW_PARBIT_PERIOD_SIZE |
-                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
-                                SND_PCM_HW_PARBIT_PERIODS |
-                                SND_PCM_HW_PARBIT_PERIOD_TIME |
-                                SND_PCM_HW_PARBIT_BUFFER_TIME |
-                                SND_PCM_HW_PARBIT_TICK_TIME);
-       params->cmask |= lcmask;
+       err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
+                                    SND_PCM_SUBFORMAT_STD, 0);
        if (err < 0)
                return err;
        params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        return 0;
 }
 
-static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
+static int snd_pcm_adpcm_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
 {
        snd_pcm_adpcm_t *adpcm = pcm->private;
-       snd_pcm_t *slave = adpcm->plug.slave;
-       int err;
-       snd_pcm_hw_params_t sparams;
-       unsigned int links;
        mask_t *saccess_mask = alloca(mask_sizeof());
        mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
+       _snd_pcm_hw_params_any(sparams);
+       _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
                                saccess_mask);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
+       _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_FORMAT,
                              adpcm->sformat, 0);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
+       _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_SUBFORMAT,
                              SND_PCM_SUBFORMAT_STD, 0);
-       links = SND_PCM_HW_PARBIT_CHANNELS |
-               SND_PCM_HW_PARBIT_RATE |
-               SND_PCM_HW_PARBIT_PERIOD_SIZE |
-               SND_PCM_HW_PARBIT_BUFFER_SIZE |
-               SND_PCM_HW_PARBIT_PERIODS |
-               SND_PCM_HW_PARBIT_PERIOD_TIME |
-               SND_PCM_HW_PARBIT_BUFFER_TIME |
-               SND_PCM_HW_PARBIT_TICK_TIME;
-       err = snd_pcm_hw_params_refine(&sparams, links, params);
-       assert(err >= 0);
-       err = snd_pcm_hw_params(slave, &sparams);
-       params->cmask = 0;
-       sparams.cmask = ~0U;
-       snd_pcm_hw_params_refine(params, links, &sparams);
+       return 0;
+}
+
+static int snd_pcm_adpcm_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+                                           snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+                             SND_PCM_HW_PARBIT_RATE |
+                             SND_PCM_HW_PARBIT_PERIOD_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_PERIODS |
+                             SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_BUFFER_TIME |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       err = _snd_pcm_hw_params_refine(sparams, links, params);
        if (err < 0)
                return err;
-       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       return 0;
+}
+       
+static int snd_pcm_adpcm_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+                                           snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+                             SND_PCM_HW_PARBIT_RATE |
+                             SND_PCM_HW_PARBIT_PERIOD_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_PERIODS |
+                             SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_BUFFER_TIME |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       err = _snd_pcm_hw_params_refine(params, links, sparams);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static int snd_pcm_adpcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       return snd_pcm_hw_refine_slave(pcm, params,
+                                      snd_pcm_adpcm_hw_refine_cprepare,
+                                      snd_pcm_adpcm_hw_refine_cchange,
+                                      snd_pcm_adpcm_hw_refine_sprepare,
+                                      snd_pcm_adpcm_hw_refine_schange,
+                                      snd_pcm_plugin_hw_refine_slave);
+}
+
+static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
+{
+       snd_pcm_adpcm_t *adpcm = pcm->private;
+       int err = snd_pcm_hw_params_slave(pcm, params,
+                                         snd_pcm_adpcm_hw_refine_cchange,
+                                         snd_pcm_adpcm_hw_refine_sprepare,
+                                         snd_pcm_adpcm_hw_refine_schange,
+                                         snd_pcm_plugin_hw_params_slave);
+       if (err < 0)
+               return err;
+
+
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
                if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
                        adpcm->getput_idx = get_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0), SND_PCM_FORMAT_S16);
index df11d7c..c9756d8 100644 (file)
@@ -211,103 +211,108 @@ static void alaw_encode(const snd_pcm_channel_area_t *src_areas,
        }
 }
 
-static int snd_pcm_alaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+static int snd_pcm_alaw_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_alaw_t *alaw = pcm->private;
-       snd_pcm_t *slave = alaw->plug.slave;
        int err;
-       unsigned int cmask, lcmask;
-       snd_pcm_hw_params_t sparams;
        mask_t *access_mask = alloca(mask_sizeof());
-       mask_t *saccess_mask = alloca(mask_sizeof());
        mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-       cmask = params->cmask;
-       params->cmask = 0;
        err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
-                                     access_mask);
+                                    access_mask);
        if (err < 0)
                return err;
        if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
                mask_t *format_mask = alloca(mask_sizeof());
                mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
-               err = _snd_pcm_hw_param_mask(params,
-                                             SND_PCM_HW_PARAM_FORMAT,
-                                             format_mask);
-               if (err < 0)
-                       return err;
+               err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT,
+                                            format_mask);
        } else {
                err = _snd_pcm_hw_param_set(params,
-                                            SND_PCM_HW_PARAM_FORMAT,
-                                            SND_PCM_FORMAT_A_LAW, 0);
-               if (err < 0)
-                       return err;
+                                           SND_PCM_HW_PARAM_FORMAT,
+                                           SND_PCM_FORMAT_A_LAW, 0);
        }
+       if (err < 0)
+               return err;
        err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
                                     SND_PCM_SUBFORMAT_STD, 0);
        if (err < 0)
                return err;
-       lcmask = params->cmask;
-       params->cmask |= cmask;
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       return 0;
+}
 
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                              saccess_mask);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
+static int snd_pcm_alaw_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
+{
+       snd_pcm_alaw_t *alaw = pcm->private;
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       _snd_pcm_hw_params_any(sparams);
+       _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_FORMAT,
                              alaw->sformat, 0);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
+       _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_SUBFORMAT,
                              SND_PCM_SUBFORMAT_STD, 0);
-       err = snd_pcm_hw_refine2(params, &sparams,
-                                snd_pcm_generic_hw_link, slave,
-                                SND_PCM_HW_PARBIT_CHANNELS |
-                                SND_PCM_HW_PARBIT_RATE |
-                                SND_PCM_HW_PARBIT_PERIOD_SIZE |
-                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
-                                SND_PCM_HW_PARBIT_PERIODS |
-                                SND_PCM_HW_PARBIT_PERIOD_TIME |
-                                SND_PCM_HW_PARBIT_BUFFER_TIME |
-                                SND_PCM_HW_PARBIT_TICK_TIME);
-       params->cmask |= lcmask;
+       return 0;
+}
+
+static int snd_pcm_alaw_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+                                           snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+                             SND_PCM_HW_PARBIT_RATE |
+                             SND_PCM_HW_PARBIT_PERIOD_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_PERIODS |
+                             SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_BUFFER_TIME |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       err = _snd_pcm_hw_params_refine(sparams, links, params);
+       if (err < 0)
+               return err;
+       return 0;
+}
+       
+static int snd_pcm_alaw_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+                                           snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+                             SND_PCM_HW_PARBIT_RATE |
+                             SND_PCM_HW_PARBIT_PERIOD_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_PERIODS |
+                             SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_BUFFER_TIME |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       err = _snd_pcm_hw_params_refine(params, links, sparams);
        if (err < 0)
                return err;
-       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        return 0;
 }
 
+static int snd_pcm_alaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       return snd_pcm_hw_refine_slave(pcm, params,
+                                      snd_pcm_alaw_hw_refine_cprepare,
+                                      snd_pcm_alaw_hw_refine_cchange,
+                                      snd_pcm_alaw_hw_refine_sprepare,
+                                      snd_pcm_alaw_hw_refine_schange,
+                                      snd_pcm_plugin_hw_refine_slave);
+}
+
 static int snd_pcm_alaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 {
        snd_pcm_alaw_t *alaw = pcm->private;
-       snd_pcm_t *slave = alaw->plug.slave;
-       int err;
-       snd_pcm_hw_params_t sparams;
-       unsigned int links;
-       mask_t *saccess_mask = alloca(mask_sizeof());
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                              saccess_mask);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
-                             alaw->sformat, 0);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
-                             SND_PCM_SUBFORMAT_STD, 0);
-       links = SND_PCM_HW_PARBIT_CHANNELS |
-               SND_PCM_HW_PARBIT_RATE |
-               SND_PCM_HW_PARBIT_PERIOD_SIZE |
-               SND_PCM_HW_PARBIT_BUFFER_SIZE |
-               SND_PCM_HW_PARBIT_PERIODS |
-               SND_PCM_HW_PARBIT_PERIOD_TIME |
-               SND_PCM_HW_PARBIT_BUFFER_TIME |
-               SND_PCM_HW_PARBIT_TICK_TIME;
-       err = snd_pcm_hw_params_refine(&sparams, links, params);
-       assert(err >= 0);
-       err = snd_pcm_hw_params(slave, &sparams);
-       params->cmask = 0;
-       sparams.cmask = ~0U;
-       snd_pcm_hw_params_refine(params, links, &sparams);
+       int err = snd_pcm_hw_params_slave(pcm, params,
+                                         snd_pcm_alaw_hw_refine_cchange,
+                                         snd_pcm_alaw_hw_refine_sprepare,
+                                         snd_pcm_alaw_hw_refine_schange,
+                                         snd_pcm_plugin_hw_params_slave);
        if (err < 0)
                return err;
-       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
                if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
                        alaw->getput_idx = get_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0), SND_PCM_FORMAT_S16);
index f04cbb9..9072b53 100644 (file)
@@ -28,62 +28,68 @@ typedef struct {
        snd_pcm_plugin_t plug;
 } snd_pcm_copy_t;
 
-static int snd_pcm_copy_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+static int snd_pcm_copy_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
 {
-       snd_pcm_copy_t *copy = pcm->private;
-       snd_pcm_t *slave = copy->plug.slave;
        int err;
-       unsigned int cmask, lcmask;
-       snd_pcm_hw_params_t sparams;
        mask_t *access_mask = alloca(mask_sizeof());
-       mask_t *saccess_mask = alloca(mask_sizeof());
        mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-       cmask = params->cmask;
-       params->cmask = 0;
        err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
                                     access_mask);
        if (err < 0)
                return err;
-       lcmask = params->cmask;
-       params->cmask |= cmask;
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                               saccess_mask);
-       err = snd_pcm_hw_refine2(params, &sparams,
-                                snd_pcm_generic_hw_link, slave, 
-                                ~SND_PCM_HW_PARBIT_ACCESS);
-       params->cmask |= lcmask;
-       if (err < 0)
-               return err;
        params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       return err;
+       return 0;
 }
 
-static int snd_pcm_copy_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+static int snd_pcm_copy_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams)
 {
-       snd_pcm_copy_t *copy = pcm->private;
-       snd_pcm_t *slave = copy->plug.slave;
-       int err;
-       unsigned int links;
-       snd_pcm_hw_params_t sparams;
        mask_t *saccess_mask = alloca(mask_sizeof());
        mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       _snd_pcm_hw_params_any(sparams);
+       _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
+                              saccess_mask);
+       return 0;
+}
 
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                               saccess_mask);
-       links = ~SND_PCM_HW_PARBIT_ACCESS;
-       err = snd_pcm_hw_params_refine(&sparams, links, params);
-       assert(err >= 0);
-       err = snd_pcm_hw_params(slave, &sparams);
-       params->cmask = 0;
-       sparams.cmask = ~0U;
-       snd_pcm_hw_params_refine(params, links, &sparams);
+static int snd_pcm_copy_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+                                         snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS;
+       err = _snd_pcm_hw_params_refine(sparams, links, params);
        if (err < 0)
                return err;
-       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       return err;
+       return 0;
+}
+       
+static int snd_pcm_copy_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+                                         snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS;
+       err = _snd_pcm_hw_params_refine(params, links, sparams);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static int snd_pcm_copy_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       return snd_pcm_hw_refine_slave(pcm, params,
+                                      snd_pcm_copy_hw_refine_cprepare,
+                                      snd_pcm_copy_hw_refine_cchange,
+                                      snd_pcm_copy_hw_refine_sprepare,
+                                      snd_pcm_copy_hw_refine_schange,
+                                      snd_pcm_plugin_hw_refine_slave);
+}
+
+static int snd_pcm_copy_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       return snd_pcm_hw_params_slave(pcm, params,
+                                      snd_pcm_copy_hw_refine_cchange,
+                                      snd_pcm_copy_hw_refine_sprepare,
+                                      snd_pcm_copy_hw_refine_schange,
+                                      snd_pcm_plugin_hw_params_slave);
 }
 
 static snd_pcm_sframes_t snd_pcm_copy_write_areas(snd_pcm_t *pcm,
index ca028bc..95c0971 100644 (file)
@@ -72,94 +72,100 @@ static void linear_transfer(const snd_pcm_channel_area_t *src_areas, snd_pcm_ufr
        }
 }
 
-static int snd_pcm_linear_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+static int snd_pcm_linear_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
 {
-       snd_pcm_linear_t *linear = pcm->private;
-       snd_pcm_t *slave = linear->plug.slave;
        int err;
-       unsigned int cmask, lcmask;
-       snd_pcm_hw_params_t sparams;
        mask_t *access_mask = alloca(mask_sizeof());
        mask_t *format_mask = alloca(mask_sizeof());
-       mask_t *saccess_mask = alloca(mask_sizeof());
        mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
        mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-       cmask = params->cmask;
-       params->cmask = 0;
        err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
-                                     access_mask);
+                                    access_mask);
        if (err < 0)
                return err;
        err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT,
-                                     format_mask);
+                                    format_mask);
        if (err < 0)
                return err;
        err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
-                                   SND_PCM_SUBFORMAT_STD, 0);
+                                    SND_PCM_SUBFORMAT_STD, 0);
        if (err < 0)
                return err;
-       lcmask = params->cmask;
-       params->cmask |= cmask;
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       return 0;
+}
 
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                               saccess_mask);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
+static int snd_pcm_linear_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
+{
+       snd_pcm_linear_t *linear = pcm->private;
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       _snd_pcm_hw_params_any(sparams);
+       _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
+                              saccess_mask);
+       _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_FORMAT,
                              linear->sformat, 0);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
+       _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_SUBFORMAT,
                              SND_PCM_SUBFORMAT_STD, 0);
-       err = snd_pcm_hw_refine2(params, &sparams,
-                                snd_pcm_generic_hw_link, slave,
-                                SND_PCM_HW_PARBIT_CHANNELS |
-                                SND_PCM_HW_PARBIT_RATE |
-                                SND_PCM_HW_PARBIT_PERIOD_SIZE |
-                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
-                                SND_PCM_HW_PARBIT_PERIODS |
-                                SND_PCM_HW_PARBIT_PERIOD_TIME |
-                                SND_PCM_HW_PARBIT_BUFFER_TIME |
-                                SND_PCM_HW_PARBIT_TICK_TIME);
-       params->cmask |= lcmask;
+       return 0;
+}
+
+static int snd_pcm_linear_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+                                           snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+                             SND_PCM_HW_PARBIT_RATE |
+                             SND_PCM_HW_PARBIT_PERIOD_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_PERIODS |
+                             SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_BUFFER_TIME |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       err = _snd_pcm_hw_params_refine(sparams, links, params);
+       if (err < 0)
+               return err;
+       return 0;
+}
+       
+static int snd_pcm_linear_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+                                           snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+                             SND_PCM_HW_PARBIT_RATE |
+                             SND_PCM_HW_PARBIT_PERIOD_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_PERIODS |
+                             SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_BUFFER_TIME |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       err = _snd_pcm_hw_params_refine(params, links, sparams);
        if (err < 0)
                return err;
-       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        return 0;
 }
 
+static int snd_pcm_linear_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       return snd_pcm_hw_refine_slave(pcm, params,
+                                      snd_pcm_linear_hw_refine_cprepare,
+                                      snd_pcm_linear_hw_refine_cchange,
+                                      snd_pcm_linear_hw_refine_sprepare,
+                                      snd_pcm_linear_hw_refine_schange,
+                                      snd_pcm_plugin_hw_refine_slave);
+}
+
 static int snd_pcm_linear_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_linear_t *linear = pcm->private;
-       snd_pcm_t *slave = linear->plug.slave;
-       int err;
-       unsigned int links;
-       snd_pcm_hw_params_t sparams;
-       mask_t *saccess_mask = alloca(mask_sizeof());
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                               saccess_mask);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
-                             linear->sformat, 0);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
-                              SND_PCM_SUBFORMAT_STD, 0);
-       links = SND_PCM_HW_PARBIT_CHANNELS |
-               SND_PCM_HW_PARBIT_RATE |
-               SND_PCM_HW_PARBIT_PERIOD_SIZE |
-               SND_PCM_HW_PARBIT_BUFFER_SIZE |
-               SND_PCM_HW_PARBIT_PERIODS |
-               SND_PCM_HW_PARBIT_PERIOD_TIME |
-               SND_PCM_HW_PARBIT_BUFFER_TIME |
-               SND_PCM_HW_PARBIT_TICK_TIME;
-       err = snd_pcm_hw_params_refine(&sparams, links, params);
-       assert(err >= 0);
-       err = snd_pcm_hw_params(slave, &sparams);
-       params->cmask = 0;
-       sparams.cmask = ~0U;
-       snd_pcm_hw_params_refine(params, links, &sparams);
+       int err = snd_pcm_hw_params_slave(pcm, params,
+                                         snd_pcm_linear_hw_refine_cchange,
+                                         snd_pcm_linear_hw_refine_sprepare,
+                                         snd_pcm_linear_hw_refine_schange,
+                                         snd_pcm_plugin_hw_params_slave);
        if (err < 0)
                return err;
-       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
                linear->conv_idx = conv_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0),
                                              linear->sformat);
index 6ffc08e..3a5dfe4 100644 (file)
@@ -299,7 +299,33 @@ static inline int muldiv_near(int a, int b, int c)
        return n;
 }
 
-int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params);
+int snd_pcm_hw_refine_soft(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
+int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                           int (*cprepare)(snd_pcm_t *pcm,
+                                           snd_pcm_hw_params_t *params),
+                           int (*cchange)(snd_pcm_t *pcm,
+                                          snd_pcm_hw_params_t *params,
+                                          snd_pcm_hw_params_t *sparams),
+                           int (*sprepare)(snd_pcm_t *pcm,
+                                           snd_pcm_hw_params_t *params),
+                           int (*schange)(snd_pcm_t *pcm,
+                                          snd_pcm_hw_params_t *params,
+                                          snd_pcm_hw_params_t *sparams),
+                           int (*srefine)(snd_pcm_t *pcm,
+                                          snd_pcm_hw_params_t *sparams));
+int snd_pcm_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                           int (*cchange)(snd_pcm_t *pcm,
+                                          snd_pcm_hw_params_t *params,
+                                          snd_pcm_hw_params_t *sparams),
+                           int (*sprepare)(snd_pcm_t *pcm,
+                                           snd_pcm_hw_params_t *params),
+                           int (*schange)(snd_pcm_t *pcm,
+                                          snd_pcm_hw_params_t *params,
+                                          snd_pcm_hw_params_t *sparams),
+                           int (*sparams)(snd_pcm_t *pcm,
+                                          snd_pcm_hw_params_t *sparams));
+
+
 void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params);
 int _snd_pcm_hw_param_refine_interval(snd_pcm_hw_params_t *params,
                                      snd_pcm_hw_param_t var,
@@ -316,34 +342,16 @@ int _snd_pcm_hw_param_min(snd_pcm_hw_params_t *params,
                           unsigned int var, unsigned int val, int dir);
 int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params,
                           unsigned int var, unsigned int val, int dir);
-int snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
-                           snd_pcm_hw_param_t var,
-                           const snd_pcm_hw_params_t *src);
-int snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
-                            unsigned int vars,
+int _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
+                            snd_pcm_hw_param_t var,
                             const snd_pcm_hw_params_t *src);
-int snd_pcm_generic_hw_link(snd_pcm_hw_params_t *params,
-                           snd_pcm_hw_params_t *sparams,
-                           snd_pcm_t *slave,
-                           unsigned long links);
-int snd_pcm_hw_refine2(snd_pcm_hw_params_t *params,
-                      snd_pcm_hw_params_t *sparams,
-                      int (*func)(snd_pcm_hw_params_t *params,
-                                  snd_pcm_hw_params_t *sparams,
-                                  snd_pcm_t *slave,
-                                  unsigned long private),
-                      snd_pcm_t *slave,
-                      unsigned long private);
-int snd_pcm_hw_params2(snd_pcm_hw_params_t *params,
-                      snd_pcm_hw_params_t *sparams,
-                      int (*func)(snd_pcm_t *slave, 
-                                  snd_pcm_hw_params_t *sparams),
-                      snd_pcm_t *slave,
-                      unsigned int links);
-void snd_pcm_hw_param_near_copy(snd_pcm_t *pcm,
-                               snd_pcm_hw_params_t *params,
-                               snd_pcm_hw_param_t var,
-                               const snd_pcm_hw_params_t *src);
+int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
+                             unsigned int vars,
+                             const snd_pcm_hw_params_t *src);
+void snd_pcm_hw_param_refine_near(snd_pcm_t *pcm,
+                                 snd_pcm_hw_params_t *params,
+                                 snd_pcm_hw_param_t var,
+                                 const snd_pcm_hw_params_t *src);
 int snd_pcm_hw_param_always_eq(const snd_pcm_hw_params_t *params,
                               snd_pcm_hw_param_t var,
                               const snd_pcm_hw_params_t *params1);
index c1a7ccb..b501e66 100644 (file)
@@ -228,19 +228,12 @@ static void mulaw_encode(const snd_pcm_channel_area_t *src_areas,
        }
 }
 
-static int snd_pcm_mulaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+static int snd_pcm_mulaw_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_mulaw_t *mulaw = pcm->private;
-       snd_pcm_t *slave = mulaw->plug.slave;
        int err;
-       unsigned int cmask, lcmask;
-       snd_pcm_hw_params_t sparams;
        mask_t *access_mask = alloca(mask_sizeof());
-       mask_t *saccess_mask = alloca(mask_sizeof());
        mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-       cmask = params->cmask;
-       params->cmask = 0;
        err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
                                     access_mask);
        if (err < 0)
@@ -248,83 +241,93 @@ static int snd_pcm_mulaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
        if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
                mask_t *format_mask = alloca(mask_sizeof());
                mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
-               err = _snd_pcm_hw_param_mask(params,
-                                            SND_PCM_HW_PARAM_FORMAT,
+               err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT,
                                             format_mask);
-               if (err < 0)
-                       return err;
        } else {
                err = _snd_pcm_hw_param_set(params,
                                            SND_PCM_HW_PARAM_FORMAT,
                                            SND_PCM_FORMAT_MU_LAW, 0);
-               if (err < 0)
-                       return err;
        }
        err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
-                                   SND_PCM_SUBFORMAT_STD, 0);
+                                    SND_PCM_SUBFORMAT_STD, 0);
        if (err < 0)
                return err;
-       lcmask = params->cmask;
-       params->cmask |= cmask;
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       return 0;
+}
 
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                              saccess_mask);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
+static int snd_pcm_mulaw_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
+{
+       snd_pcm_mulaw_t *mulaw = pcm->private;
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       _snd_pcm_hw_params_any(sparams);
+       _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_FORMAT,
                              mulaw->sformat, 0);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
+       _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_SUBFORMAT,
                              SND_PCM_SUBFORMAT_STD, 0);
-       err = snd_pcm_hw_refine2(params, &sparams,
-                                snd_pcm_generic_hw_link, slave,
-                                SND_PCM_HW_PARBIT_CHANNELS |
-                                SND_PCM_HW_PARBIT_RATE |
-                                SND_PCM_HW_PARBIT_PERIOD_SIZE |
-                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
-                                SND_PCM_HW_PARBIT_PERIODS |
-                                SND_PCM_HW_PARBIT_PERIOD_TIME |
-                                SND_PCM_HW_PARBIT_BUFFER_TIME |
-                                SND_PCM_HW_PARBIT_TICK_TIME);
-       params->cmask |= lcmask;
+       return 0;
+}
+
+static int snd_pcm_mulaw_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+                                           snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+                             SND_PCM_HW_PARBIT_RATE |
+                             SND_PCM_HW_PARBIT_PERIOD_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_PERIODS |
+                             SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_BUFFER_TIME |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       err = _snd_pcm_hw_params_refine(sparams, links, params);
        if (err < 0)
                return err;
-       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        return 0;
 }
+       
+static int snd_pcm_mulaw_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+                                           snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+                             SND_PCM_HW_PARBIT_RATE |
+                             SND_PCM_HW_PARBIT_PERIOD_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_PERIODS |
+                             SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_BUFFER_TIME |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       err = _snd_pcm_hw_params_refine(params, links, sparams);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static int snd_pcm_mulaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       return snd_pcm_hw_refine_slave(pcm, params,
+                                      snd_pcm_mulaw_hw_refine_cprepare,
+                                      snd_pcm_mulaw_hw_refine_cchange,
+                                      snd_pcm_mulaw_hw_refine_sprepare,
+                                      snd_pcm_mulaw_hw_refine_schange,
+                                      snd_pcm_plugin_hw_refine_slave);
+}
 
 static int snd_pcm_mulaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 {
        snd_pcm_mulaw_t *mulaw = pcm->private;
-       snd_pcm_t *slave = mulaw->plug.slave;
-       int err;
-       unsigned int links;
-       snd_pcm_hw_params_t sparams;
-       mask_t *saccess_mask = alloca(mask_sizeof());
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                              saccess_mask);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
-                             mulaw->sformat, 0);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
-                             SND_PCM_SUBFORMAT_STD, 0);
-       links = SND_PCM_HW_PARBIT_CHANNELS |
-               SND_PCM_HW_PARBIT_RATE |
-               SND_PCM_HW_PARBIT_PERIOD_SIZE |
-               SND_PCM_HW_PARBIT_BUFFER_SIZE |
-               SND_PCM_HW_PARBIT_PERIODS |
-               SND_PCM_HW_PARBIT_PERIOD_TIME |
-               SND_PCM_HW_PARBIT_BUFFER_TIME |
-               SND_PCM_HW_PARBIT_TICK_TIME;
-       err = snd_pcm_hw_params_refine(&sparams, links, params);
-       assert(err >= 0);
-       err = snd_pcm_hw_params(slave, &sparams);
-       params->cmask = 0;
-       sparams.cmask = ~0U;
-       snd_pcm_hw_params_refine(params, links, &sparams);
+       int err = snd_pcm_hw_params_slave(pcm, params,
+                                         snd_pcm_mulaw_hw_refine_cchange,
+                                         snd_pcm_mulaw_hw_refine_sprepare,
+                                         snd_pcm_mulaw_hw_refine_schange,
+                                         snd_pcm_plugin_hw_params_slave);
        if (err < 0)
                return err;
-       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
                if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
                        mulaw->getput_idx = get_index(snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0), SND_PCM_FORMAT_S16);
index e5018f3..53fbbc8 100644 (file)
@@ -69,7 +69,10 @@ static int snd_pcm_multi_close(snd_pcm_t *pcm)
 
 static int snd_pcm_multi_card(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 {
-       return -ENOENT; /* not available */
+       snd_pcm_multi_t *multi = pcm->private;
+       if (multi->slaves_count != 1)
+               return -ENOENT; /* not available */
+       return snd_pcm_card(multi->slaves[0].pcm);
 }
 
 static int snd_pcm_multi_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
@@ -96,135 +99,188 @@ static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
        return 0;
 }
 
-static int snd_pcm_multi_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+static int snd_pcm_multi_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_multi_t *multi = pcm->private;
-       unsigned int k;
-       snd_pcm_hw_params_t sparams;
-       int changed = 0;
-       int err = 0;
-       unsigned int cmask, lcmask;
-       const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
-       mask_t *saccess_mask = alloca(mask_sizeof());
-       if (mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) ||
-           mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
-               mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-       else {
-               mask_none(saccess_mask);
-               if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED) &&
-                   multi->slaves_count == 1)
-                       mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
-               if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
-                       mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
-               if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX)) {
-                       mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
-                       if (multi->slaves_count > 1)
-                               mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
-               }
-       }
-               
-       cmask = params->cmask;
-       params->cmask = 0;
+       mask_t *access_mask = alloca(mask_sizeof());
+       int err;
+       mask_any(access_mask);
+       mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+       err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
+                                    access_mask);
+       if (err < 0)
+               return err;
        err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS,
                                    multi->channels_count, 0);
        if (err < 0)
                return err;
-       lcmask = params->cmask;
-       cmask |= params->cmask;
+       params->info = ~0;
+       return 0;
+}
+
+static int snd_pcm_multi_hw_refine_sprepare(snd_pcm_t *pcm, int slave_idx,
+                                           snd_pcm_hw_params_t *sparams)
+{
+       snd_pcm_multi_t *multi = pcm->private;
+       snd_pcm_multi_slave_t *slave = &multi->slaves[slave_idx];
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       _snd_pcm_hw_params_any(sparams);
+       _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
+                              saccess_mask);
+       _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS,
+                             slave->channels_count, 0);
+       return 0;
+}
+
+static int snd_pcm_multi_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
+                                          int slave_idx ATTRIBUTE_UNUSED,
+                                          snd_pcm_hw_params_t *params,
+                                          snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = (SND_PCM_HW_PARBIT_FORMAT |
+                             SND_PCM_HW_PARBIT_SUBFORMAT |
+                             SND_PCM_HW_PARBIT_RATE |
+                             SND_PCM_HW_PARBIT_PERIOD_SIZE |
+                             SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_PERIODS |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_TIME |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
+       if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
+           !mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) &&
+           !mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) {
+               mask_t *saccess_mask = alloca(mask_sizeof());
+               mask_any(saccess_mask);
+               mask_reset(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+               err = _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
+                                            saccess_mask);
+               if (err < 0)
+                       return err;
+       }
+       err = _snd_pcm_hw_params_refine(sparams, links, params);
+       if (err < 0)
+               return err;
+       return 0;
+}
        
-       changed = 0;
-       do {
-               for (k = 0; k < multi->slaves_count; ++k) {
-                       snd_pcm_t *slave = multi->slaves[k].pcm;
-                       params->cmask = cmask;
-                       _snd_pcm_hw_params_any(&sparams);
-                       _snd_pcm_hw_param_mask(&sparams,
-                                              SND_PCM_HW_PARAM_ACCESS,
-                                              saccess_mask);
-                       _snd_pcm_hw_param_set(&sparams,
-                                             SND_PCM_HW_PARAM_CHANNELS,
-                                             multi->slaves[k].channels_count, 0);
-                       err = snd_pcm_hw_refine2(params, &sparams,
-                                                snd_pcm_generic_hw_link, slave,
-                                                SND_PCM_HW_PARBIT_FORMAT |
-                                                SND_PCM_HW_PARBIT_SUBFORMAT |
-                                                SND_PCM_HW_PARBIT_RATE |
-                                                SND_PCM_HW_PARBIT_PERIOD_SIZE |
-                                                SND_PCM_HW_PARBIT_PERIOD_TIME |
-                                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
-                                                SND_PCM_HW_PARBIT_BUFFER_TIME |
-                                                SND_PCM_HW_PARBIT_PERIODS |
-                                                SND_PCM_HW_PARBIT_TICK_TIME);
-                       if (params->cmask) {
-                               changed++;
-                               lcmask |= params->cmask;
-                               cmask |= params->cmask;
-                       }
-                       if (err < 0)
-                               goto _end;
-               }
-       } while (changed && multi->slaves_count > 1);
- _end:
-       params->cmask = lcmask;
-       return err;
+static int snd_pcm_multi_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
+                                          int slave_idx ATTRIBUTE_UNUSED,
+                                          snd_pcm_hw_params_t *params,
+                                          snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = (SND_PCM_HW_PARBIT_FORMAT |
+                             SND_PCM_HW_PARBIT_SUBFORMAT |
+                             SND_PCM_HW_PARBIT_RATE |
+                             SND_PCM_HW_PARBIT_PERIOD_SIZE |
+                             SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_PERIODS |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_TIME |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       mask_t *access_mask = alloca(mask_sizeof());
+       const mask_t *saccess_mask = snd_pcm_hw_param_value_mask(sparams, SND_PCM_HW_PARAM_ACCESS);
+       mask_any(access_mask);
+       mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+       if (!mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
+               mask_reset(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+       if (!mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX) &&
+           !mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED))
+               mask_reset(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
+       err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
+                                    access_mask);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_refine(params, links, sparams);
+       if (err < 0)
+               return err;
+       params->info &= sparams->info;
+       return 0;
 }
 
-static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+static int snd_pcm_multi_hw_refine_slave(snd_pcm_t *pcm,
+                                        int slave_idx,
+                                        snd_pcm_hw_params_t *sparams)
+{
+       snd_pcm_multi_t *multi = pcm->private;
+       snd_pcm_t *slave = multi->slaves[slave_idx].pcm;
+       return snd_pcm_hw_refine(slave, sparams);
+}
+
+static int snd_pcm_multi_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_multi_t *multi = pcm->private;
        unsigned int k;
+       snd_pcm_hw_params_t sparams[multi->slaves_count];
        int err;
-       const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
-       mask_t *saccess_mask = alloca(mask_sizeof());
-       unsigned int links;
-       links = SND_PCM_HW_PARBIT_FORMAT |
-               SND_PCM_HW_PARBIT_SUBFORMAT |
-               SND_PCM_HW_PARBIT_RATE |
-               SND_PCM_HW_PARBIT_PERIOD_SIZE |
-               SND_PCM_HW_PARBIT_PERIOD_TIME |
-               SND_PCM_HW_PARBIT_BUFFER_SIZE |
-               SND_PCM_HW_PARBIT_BUFFER_TIME |
-               SND_PCM_HW_PARBIT_PERIODS |
-               SND_PCM_HW_PARBIT_TICK_TIME;
-       if (mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) ||
-           mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
-               mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-       else {
-               mask_none(saccess_mask);
-               if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED) &&
-                   multi->slaves_count == 1)
-                       mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
-               if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
-                       mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
-               if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX)) {
-                       mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
-                       if (multi->slaves_count > 1)
-                               mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+       err = snd_pcm_multi_hw_refine_cprepare(pcm, params);
+       if (err < 0)
+               return err;
+       for (k = 0; k < multi->slaves_count; ++k) {
+               err = snd_pcm_multi_hw_refine_sprepare(pcm, k, &sparams[k]);
+               if (err < 0) {
+                       ERR("Slave PCM #%d not useable", k);
+                       return err;
                }
        }
+       /* FIXME: loop begin? */
        for (k = 0; k < multi->slaves_count; ++k) {
-               snd_pcm_t *slave = multi->slaves[k].pcm;
-               snd_pcm_hw_params_t sparams;
-               _snd_pcm_hw_params_any(&sparams);
-               _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                                       saccess_mask);
-               _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_CHANNELS,
-                                      multi->slaves[k].channels_count, 0);
-               err = snd_pcm_hw_params_refine(&sparams, links, params);
-               assert(err >= 0);
-               err = snd_pcm_hw_params(slave, &sparams);
-               params->cmask = 0;
-               sparams.cmask = ~0U;
-               snd_pcm_hw_params_refine(params, links, &sparams);
+               err = snd_pcm_multi_hw_refine_schange(pcm, k, params, &sparams[k]);
+               if (err >= 0)
+                       err = snd_pcm_multi_hw_refine_slave(pcm, k, &sparams[k]);
+               if (err < 0) {
+                       snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]);
+                       return err;
+               }
+               err = snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]);
                if (err < 0)
                        return err;
-               err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format);
+       }
+       err = snd_pcm_hw_refine_soft(pcm, params);
+       if (err < 0)
+               return err;
+       /* FIXME: do we need to loop? */
+       return 0;
+}
+
+static int snd_pcm_multi_hw_params_slave(snd_pcm_t *pcm,
+                                        int slave_idx,
+                                        snd_pcm_hw_params_t *sparams)
+{
+       snd_pcm_multi_t *multi = pcm->private;
+       snd_pcm_t *slave = multi->slaves[slave_idx].pcm;
+       int err = snd_pcm_hw_refine(slave, sparams);
+       if (err < 0)
+               return err;
+       err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format);
+       if (err < 0)
+               return err;
+       if (slave->stopped_areas) {
+               err = snd_pcm_areas_silence(slave->stopped_areas, 0, slave->channels, slave->buffer_size, slave->format);
                if (err < 0)
                        return err;
-               if (slave->stopped_areas) {
-                       err = snd_pcm_areas_silence(slave->stopped_areas, 0, slave->channels, slave->buffer_size, slave->format);
-                       if (err < 0)
-                               return err;
+       }
+       return 0;
+}
+
+static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       snd_pcm_multi_t *multi = pcm->private;
+       unsigned int k;
+       snd_pcm_hw_params_t sparams[multi->slaves_count];
+       int err;
+       for (k = 0; k < multi->slaves_count; ++k) {
+               err = snd_pcm_multi_hw_refine_sprepare(pcm, k, &sparams[k]);
+               assert(err >= 0);
+               err = snd_pcm_multi_hw_refine_schange(pcm, k, params, &sparams[k]);
+               assert(err >= 0);
+               err = snd_pcm_multi_hw_params_slave(pcm, k, &sparams[k]);
+               if (err < 0) {
+                       snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]);
+                       return err;
                }
        }
        return 0;
index 1007a9d..1f46659 100644 (file)
@@ -231,7 +231,7 @@ static snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm)
 
 static int snd_pcm_null_hw_refine(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
 {
-       int err = _snd_pcm_hw_refine(params);
+       int err = snd_pcm_hw_refine_soft(pcm, params);
        params->fifo_size = 0;
        return err;
 }
index 7bbcab7..b2fe8a0 100644 (file)
@@ -115,11 +115,13 @@ void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var)
        if (hw_is_mask(var)) {
                mask_any(hw_param_mask(params, var));
                params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
                return;
        }
        if (hw_is_interval(var)) {
                interval_any(hw_param_interval(params, var));
                params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
                return;
        }
        assert(0);
@@ -241,8 +243,10 @@ int _snd_pcm_hw_param_refine_interval(snd_pcm_hw_params_t *params,
        int changed;
        assert(hw_is_interval(var));
        changed = interval_refine(hw_param_interval(params, var), val);
-       if (changed)
+       if (changed) {
                params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
        return changed;
 }
 
@@ -252,8 +256,10 @@ int _snd_pcm_hw_param_setinteger(snd_pcm_hw_params_t *params,
        int changed;
        assert(hw_is_interval(var));
        changed = interval_setinteger(hw_param_interval(params, var));
-       if (changed)
+       if (changed) {
                params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
        return changed;
 }
        
@@ -268,7 +274,7 @@ int snd_pcm_hw_param_setinteger(snd_pcm_t *pcm,
        int changed = _snd_pcm_hw_param_setinteger(params, var);
        if (changed < 0)
                return changed;
-       if (changed) {
+       if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
                if (err < 0)
                        return err;
@@ -288,8 +294,10 @@ int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params,
                assert(0);
                return -EINVAL;
        }
-       if (changed)
+       if (changed) {
                params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
        return changed;
 }
 
@@ -305,7 +313,7 @@ int snd_pcm_hw_param_first(snd_pcm_t *pcm,
        int changed = _snd_pcm_hw_param_first(params, var);
        if (changed < 0)
                return changed;
-       if (changed) {
+       if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
                assert(err >= 0);
        }
@@ -324,8 +332,10 @@ int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params,
                assert(0);
                return -EINVAL;
        }
-       if (changed)
+       if (changed) {
                params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
        return changed;
 }
 
@@ -341,7 +351,7 @@ int snd_pcm_hw_param_last(snd_pcm_t *pcm,
        int changed = _snd_pcm_hw_param_last(params, var);
        if (changed < 0)
                return changed;
-       if (changed) {
+       if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
                assert(err >= 0);
        }
@@ -371,8 +381,10 @@ int _snd_pcm_hw_param_min(snd_pcm_hw_params_t *params,
                assert(0);
                return -EINVAL;
        }
-       if (changed)
+       if (changed) {
                params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
        return changed;
 }
 
@@ -386,7 +398,7 @@ int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
        int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
        if (changed < 0)
                return changed;
-       if (changed) {
+       if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
                if (err < 0)
                        return err;
@@ -432,8 +444,10 @@ int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params,
                assert(0);
                return -EINVAL;
        }
-       if (changed)
+       if (changed) {
                params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
        return changed;
 }
 
@@ -447,7 +461,7 @@ int snd_pcm_hw_param_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
        int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
        if (changed < 0)
                return changed;
-       if (changed) {
+       if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
                if (err < 0)
                        return err;
@@ -527,8 +541,10 @@ int _snd_pcm_hw_param_minmax(snd_pcm_hw_params_t *params,
                assert(0);
                return -EINVAL;
        }
-       if (changed)
+       if (changed) {
                params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
        return changed;
 }
 
@@ -546,7 +562,7 @@ int snd_pcm_hw_param_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
                                               *max, maxdir ? *maxdir : 0);
        if (changed < 0)
                return changed;
-       if (changed) {
+       if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
                if (err < 0)
                        return err;
@@ -614,8 +630,10 @@ int _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params,
                assert(0);
                return -EINVAL;
        }
-       if (changed)
+       if (changed) {
                params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
        return changed;
 }
 
@@ -629,7 +647,7 @@ int snd_pcm_hw_param_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
        int changed = _snd_pcm_hw_param_set(params, var, val, dir);
        if (changed < 0)
                return changed;
-       if (changed) {
+       if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
                if (err < 0)
                        return err;
@@ -655,8 +673,10 @@ int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params,
        int changed;
        assert(hw_is_mask(var));
        changed = mask_refine(hw_param_mask(params, var), val);
-       if (changed)
+       if (changed) {
                params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
        return changed;
 }
 
@@ -673,7 +693,7 @@ int snd_pcm_hw_param_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
        int changed = _snd_pcm_hw_param_mask(params, var, val);
        if (changed < 0)
                return changed;
-       if (changed) {
+       if (params->rmask) {
                int err = snd_pcm_hw_refine(pcm, params);
                if (err < 0)
                        return err;
@@ -706,7 +726,6 @@ int snd_pcm_hw_param_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
        int v;
        unsigned int saved_min;
        int last = 0;
-       unsigned int cmask;
        int min, max;
        int mindir, maxdir;
        int valdir = dir ? *dir : 0;
@@ -747,12 +766,10 @@ int snd_pcm_hw_param_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
                last = 1;
        }
  _end:
-       cmask = params->cmask;
        if (last)
                v = snd_pcm_hw_param_last(pcm, params, var, dir);
        else
                v = snd_pcm_hw_param_first(pcm, params, var, dir);
-       params->cmask |= cmask;
        assert(v >= 0);
        return v;
 }
@@ -773,7 +790,6 @@ int snd_pcm_hw_param_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
        snd_pcm_hw_params_t save;
        int v;
        int last = 0;
-       unsigned int cmask;
        int min, max;
        int mindir, maxdir;
        int diff, diffdir;
@@ -821,12 +837,10 @@ int snd_pcm_hw_param_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
                last = 1;
        }
  _end:
-       cmask = params->cmask;
        if (last)
                v = snd_pcm_hw_param_last(pcm, params, var, dir);
        else
                v = snd_pcm_hw_param_first(pcm, params, var, dir);
-       params->cmask |= cmask;
        assert(v >= 0);
        return v;
 }
@@ -857,10 +871,10 @@ void snd_pcm_hw_param_near_minmax(snd_pcm_t *pcm,
        assert(err >= 0);
 }
 
-void snd_pcm_hw_param_near_copy(snd_pcm_t *pcm,
-                               snd_pcm_hw_params_t *params,
-                               snd_pcm_hw_param_t var,
-                               const snd_pcm_hw_params_t *src)
+void snd_pcm_hw_param_refine_near(snd_pcm_t *pcm,
+                                 snd_pcm_hw_params_t *params,
+                                 snd_pcm_hw_param_t var,
+                                 const snd_pcm_hw_params_t *src)
 {
        unsigned int min, max;
        int mindir, maxdir;
@@ -963,41 +977,30 @@ int snd_pcm_hw_params_info_fifo_size(const snd_pcm_hw_params_t *params)
 void snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        int err;
-       unsigned int cmask = params->cmask;
 
        err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_ACCESS, 0);
        assert(err >= 0);
-       cmask |= params->cmask;
 
        err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_FORMAT, 0);
        assert(err >= 0);
-       cmask |= params->cmask;
 
        err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT, 0);
        assert(err >= 0);
-       cmask |= params->cmask;
 
        err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_CHANNELS, 0);
        assert(err >= 0);
-       cmask |= params->cmask;
 
        err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_RATE, 0);
        assert(err >= 0);
-       cmask |= params->cmask;
 
        err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_PERIOD_TIME, 0);
        assert(err >= 0);
-       cmask |= params->cmask;
 
        err = snd_pcm_hw_param_last(pcm, params, SND_PCM_HW_PARAM_BUFFER_SIZE, 0);
        assert(err >= 0);
-       cmask |= params->cmask;
 
        err = snd_pcm_hw_param_first(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, 0);
        assert(err >= 0);
-       cmask |= params->cmask;
-
-       params->cmask = cmask;
 }
 
 /* Strategies */
@@ -1080,9 +1083,9 @@ unsigned int snd_pcm_hw_param_count(const snd_pcm_hw_params_t *params,
        return 0;
 }
 
-int snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
-                           snd_pcm_hw_param_t var,
-                           const snd_pcm_hw_params_t *src)
+int _snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
+                            snd_pcm_hw_param_t var,
+                            const snd_pcm_hw_params_t *src)
 {
        int changed = 0;
        if (hw_is_mask(var)) {
@@ -1095,23 +1098,29 @@ int snd_pcm_hw_param_refine(snd_pcm_hw_params_t *params,
                changed = interval_refine(d, s);
        } else
                assert(0);
-       if (changed)
+       if (changed) {
                params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
        return changed;
 }
                             
-void snd_pcm_hw_param_copy(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
+void _snd_pcm_hw_param_copy(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var,
                            const snd_pcm_hw_params_t *src)
 {
        if (hw_is_mask(var)) {
                mask_t *d = hw_param_mask(params, var);
                const mask_t *s = hw_param_mask_c(src, var);
                mask_copy(d, s);
+               params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
        }
        if (hw_is_interval(var)) {
                interval_t *d = hw_param_interval(params, var);
                const interval_t *s = hw_param_interval_c(src, var);
                interval_copy(d, s);
+               params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
        }
        assert(0);
 }
@@ -1138,8 +1147,11 @@ void snd_pcm_hw_param_dump(const snd_pcm_hw_params_t *params,
                        assert(f);
                        for (k = 0; k <= MASK_MAX; ++k) {
                                if (mask_test(mask, k)) {
-                                       snd_output_putc(out, ' ');
-                                       snd_output_puts(out, f(k));
+                                       const char *s = f(k);
+                                       if (s) {
+                                               snd_output_putc(out, ' ');
+                                               snd_output_puts(out, s);
+                                       }
                                }
                        }
                }
@@ -1188,14 +1200,11 @@ int snd_pcm_hw_params_strategy(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
        best_badness = UINT_MAX;
        value = -1;
        while (1) {
-               unsigned int cmask;
                params1 = *params;
                value = strategy->next_value(&params1, var, value, &dir, pcm, strategy);
                if (value < 0)
                        break;
-               cmask = params1.cmask;
                badness = snd_pcm_hw_params_strategy(pcm, &params1, strategy, badness_min, badness_max);
-               params1.cmask |= cmask;
                if (badness >= 0) {
                        if ((unsigned int) badness <= badness_min) {
                                *params = params1;
@@ -1475,7 +1484,7 @@ int snd_pcm_hw_params_try_explain_failure1(snd_pcm_t *pcm,
        for (var = 0; var <= SND_PCM_HW_PARAM_LAST; var++) {
                int err;
                i = *success;
-               snd_pcm_hw_param_copy(&i, var, fail);
+               _snd_pcm_hw_param_copy(&i, var, fail);
                err = snd_pcm_hw_refine(pcm, &i);
                if (err == 0 && 
                    snd_pcm_hw_params_try_explain_failure1(pcm, fail, &i, depth - 1, out) < 0)
@@ -1836,50 +1845,53 @@ static interval_t refine_intervals[SND_PCM_HW_PARAM_LAST_INTERVAL - SND_PCM_HW_P
        },
 };
 
+#undef RULES_DEBUG
 
-
-int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params)
+int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
 {
        unsigned int k;
        interval_t *i;
        unsigned int rstamps[RULES];
        unsigned int vstamps[SND_PCM_HW_PARAM_LAST + 1];
        unsigned int stamp = 2;
-       int err, changed;
+       int changed, again;
+#ifdef RULES_DEBUG
+       snd_output_t *log;
+       snd_output_stdio_attach(&log, stderr, 0);
+#endif
 
        for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) {
-               if (!(params->cmask & (1 << k)))
+               if (!(params->rmask & (1 << k)))
                        continue;
-               err = mask_refine(hw_param_mask(params, k),
+               changed = mask_refine(hw_param_mask(params, k),
                                  &refine_masks[k - SND_PCM_HW_PARAM_FIRST_MASK]);
-               if (err < 0)
-                       return err;
+               if (changed)
+                       params->cmask |= 1 << k;
+               if (changed < 0)
+                       goto _err;
        }
 
        for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) {
-               if (!(params->cmask & (1 << k)))
+               if (!(params->rmask & (1 << k)))
                        continue;
-               err = interval_refine(hw_param_interval(params, k),
+               changed = interval_refine(hw_param_interval(params, k),
                                      &refine_intervals[k - SND_PCM_HW_PARAM_FIRST_INTERVAL]);
-               if (err < 0)
-                       return err;
+               if (changed)
+                       params->cmask |= 1 << k;
+               if (changed < 0)
+                       goto _err;
        }
 
        for (k = 0; k < RULES; k++)
                rstamps[k] = 0;
        for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++)
-               vstamps[k] = (params->cmask & (1 << k)) ? 1 : 0;
-       params->cmask = 0;
-       changed = 1;
-       while (changed) {
-               changed = 0;
+               vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
+       do {
+               again = 0;
                for (k = 0; k < RULES; k++) {
                        snd_pcm_hw_rule_t *r = &refine_rules[k];
                        unsigned int d;
                        int doit = 0;
-#ifdef RULES_DEBUG
-                       interval_t *i;
-#endif
                        for (d = 0; r->deps[d] >= 0; d++) {
                                if (vstamps[r->deps[d]] > rstamps[k]) {
                                        doit = 1;
@@ -1889,26 +1901,35 @@ int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params)
                        if (!doit)
                                continue;
 #ifdef RULES_DEBUG
-                       i = hw_param_interval(params, r->var);
-                       fprintf(stderr, "Rule %d: %u ", k, r->var);
-                       interval_print(i, stderr);
+                       snd_output_printf(log, "Rule %d: ", k);
+                       if (r->var >= 0) {
+                               snd_output_printf(log, "%s=", snd_pcm_hw_param_name(r->var));
+                               snd_pcm_hw_param_dump(params, r->var, log);
+                               snd_output_puts(log, " -> ");
+                       }
 #endif
-                       err = r->func(params, r);
+                       changed = r->func(params, r);
 #ifdef RULES_DEBUG
-                       interval_print(i, stderr);
-                       putc('\n', stderr);
+                       if (r->var >= 0)
+                               snd_pcm_hw_param_dump(params, r->var, log);
+                       snd_output_putc(log, ' ');
+                       for (d = 0; r->deps[d] >= 0; d++) {
+                               snd_output_printf(log, "%s=", snd_pcm_hw_param_name(r->deps[d]));
+                               snd_pcm_hw_param_dump(params, r->deps[d], log);
+                       }
+                       snd_output_putc(log, '\n');
 #endif
                        rstamps[k] = stamp;
-                       if (err && r->var >= 0) {
+                       if (changed && r->var >= 0) {
                                params->cmask |= 1 << r->var;
                                vstamps[r->var] = stamp;
-                               changed = 1;
+                               again = 1;
                        }
-                       if (err < 0)
-                               return err;
+                       if (changed < 0)
+                               goto _err;
                        stamp++;
                }
-       }
+       } while (again);
        if (!params->msbits) {
                i = hw_param_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS);
                if (interval_single(i))
@@ -1922,69 +1943,97 @@ int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params)
                        params->rate_den = 1;
                }
        }
+       params->rmask = 0;
        return 0;
+ _err:
+#ifdef RULES_DEBUG
+       snd_output_close(log);
+#endif
+       return changed;
 }
 
-int snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
-                            unsigned int vars,
-                            const snd_pcm_hw_params_t *src)
+int _snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params,
+                             unsigned int vars,
+                             const snd_pcm_hw_params_t *src)
 {
        int changed, err = 0;
        unsigned int k;
        for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
-               if (!(vars & (1 << k)) ||
-                   !((src->cmask & (1 << k))))
+               if (!(vars & (1 << k)))
                        continue;
-               changed = snd_pcm_hw_param_refine(params, k, src);
+               changed = _snd_pcm_hw_param_refine(params, k, src);
                if (changed < 0)
                        err = changed;
        }
        return err;
 }
 
-/* Accumulate to params->cmask */
-/* Reset sparams->cmask */
-int snd_pcm_generic_hw_link(snd_pcm_hw_params_t *params,
-                           snd_pcm_hw_params_t *sparams,
-                           snd_pcm_t *slave,
-                           unsigned long links)
+int snd_pcm_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                           int (*cprepare)(snd_pcm_t *pcm,
+                                           snd_pcm_hw_params_t *params),
+                           int (*cchange)(snd_pcm_t *pcm,
+                                          snd_pcm_hw_params_t *params,
+                                          snd_pcm_hw_params_t *sparams),
+                           int (*sprepare)(snd_pcm_t *pcm,
+                                           snd_pcm_hw_params_t *params),
+                           int (*schange)(snd_pcm_t *pcm,
+                                          snd_pcm_hw_params_t *params,
+                                          snd_pcm_hw_params_t *sparams),
+                           int (*srefine)(snd_pcm_t *pcm,
+                                          snd_pcm_hw_params_t *sparams))
+
 {
-       int err1, err = 0;
-       err = snd_pcm_hw_params_refine(sparams, links, params);
+       snd_pcm_hw_params_t sparams;
+       int err;
+       err = cprepare(pcm, params);
+       if (err < 0)
+               return err;
+       err = sprepare(pcm, &sparams);
+       if (err < 0) {
+               ERR("Slave PCM not useable");
+               return err;
+       }
+       /* FIXME: loop begin? */
+       err = schange(pcm, params, &sparams);
        if (err >= 0) {
-               unsigned int cmask = sparams->cmask;
-               err = snd_pcm_hw_refine(slave, sparams);
-               sparams->cmask |= cmask;
-       }
-       err1 = snd_pcm_hw_params_refine(params, links, sparams);
-       if (err1 < 0)
-               err = err1;
-       sparams->cmask = 0;
-       return err;
+               err = srefine(pcm, &sparams);
+       }
+       if (err < 0) {
+               cchange(pcm, params, &sparams);
+               return err;
+       }
+       err = cchange(pcm, params, &sparams);
+       if (err < 0)
+               return err;
+       err = snd_pcm_hw_refine_soft(pcm, params);
+       if (err < 0)
+               return err;
+       /* FIXME: do we need to loop? */
+       return 0;
 }
 
-int snd_pcm_hw_refine2(snd_pcm_hw_params_t *params,
-                      snd_pcm_hw_params_t *sparams,
-                      int (*func)(snd_pcm_hw_params_t *params,
-                                  snd_pcm_hw_params_t *sparams,
-                                  snd_pcm_t *slave,
-                                  unsigned long private),
-                      snd_pcm_t *slave,
-                      unsigned long private)
-{
-       int err = 0;
-       unsigned int cmask = 0;
-       while (params->cmask) {
-               err = func(params, sparams, slave, private);
-               cmask |= params->cmask;
-               if (err < 0)
-                       break;
-               err = _snd_pcm_hw_refine(params);
-               cmask |= params->cmask;
-               if (err < 0)
-                       break;
-       }
-       params->cmask = cmask;
+int snd_pcm_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                           int (*cchange)(snd_pcm_t *pcm,
+                                          snd_pcm_hw_params_t *params,
+                                          snd_pcm_hw_params_t *sparams),
+                           int (*sprepare)(snd_pcm_t *pcm,
+                                           snd_pcm_hw_params_t *params),
+                           int (*schange)(snd_pcm_t *pcm,
+                                          snd_pcm_hw_params_t *params,
+                                          snd_pcm_hw_params_t *sparams),
+                           int (*sparams)(snd_pcm_t *pcm,
+                                          snd_pcm_hw_params_t *sparams))
+
+{
+       snd_pcm_hw_params_t slave_params;
+       int err;
+       err = sprepare(pcm, &slave_params);
+       assert(err >= 0);
+       err = schange(pcm, params, &slave_params);
+       assert(err >= 0);
+       err = sparams(pcm, &slave_params);
+       if (err < 0)
+               cchange(pcm, params, &slave_params);
        return err;
 }
 
index 9c6bc2f..6ee9644 100644 (file)
@@ -192,182 +192,6 @@ static int snd_pcm_plug_slave_format(int format, const mask_t *format_mask)
                             (1 << SND_PCM_FORMAT_IMA_ADPCM))
 
 
-/* Accumulate to params->cmask */
-/* Reset sparams->cmask */
-static int snd_pcm_plug_hw_link(snd_pcm_hw_params_t *params,
-                               snd_pcm_hw_params_t *sparams,
-                               snd_pcm_t *slave,
-                               unsigned long private ATTRIBUTE_UNUSED)
-{
-       int rate_always, channels_always, format_always;
-       int rate_never, channels_never, format_never;
-       unsigned int links = (SND_PCM_HW_PARBIT_PERIOD_TIME |
-                             SND_PCM_HW_PARBIT_TICK_TIME);
-       const mask_t *format_mask, *sformat_mask;
-       mask_t *fmt_mask = alloca(mask_sizeof());
-       mask_t *sfmt_mask = alloca(mask_sizeof());
-       mask_t *access_mask = alloca(mask_sizeof());
-       int err;
-       unsigned int format;
-       unsigned int scmask = sparams->cmask;
-       snd_pcm_hw_param_near_copy(slave, sparams, SND_PCM_HW_PARAM_RATE,
-                                  params);
-       scmask |= sparams->cmask;
-       snd_pcm_hw_param_near_copy(slave, sparams, SND_PCM_HW_PARAM_CHANNELS,
-                                  params);
-       scmask |= sparams->cmask;
-       format_mask = snd_pcm_hw_param_value_mask(params,
-                                                  SND_PCM_HW_PARAM_FORMAT);
-       sformat_mask = snd_pcm_hw_param_value_mask(sparams,
-                                                   SND_PCM_HW_PARAM_FORMAT);
-       mask_none(sfmt_mask);
-       mask_none(fmt_mask);
-       for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
-               int f;
-               if (!mask_test(format_mask, format))
-                       continue;
-               if (mask_test(sformat_mask, format))
-                       f = format;
-               else {
-                       f = snd_pcm_plug_slave_format(format, sformat_mask);
-                       if (f < 0)
-                               continue;
-               }
-               mask_set(sfmt_mask, f);
-               mask_set(fmt_mask, format);
-       }
-
-       err = _snd_pcm_hw_param_mask(params, 
-                                    SND_PCM_HW_PARAM_FORMAT, fmt_mask);
-       if (err < 0)
-               return err;
-       err = _snd_pcm_hw_param_mask(sparams,
-                                    SND_PCM_HW_PARAM_FORMAT, sfmt_mask);
-       assert(err >= 0);
-
-       format_always = snd_pcm_hw_param_always_eq(params,
-                                                  SND_PCM_HW_PARAM_FORMAT,
-                                                  sparams);
-       format_never = (!format_always &&
-                       snd_pcm_hw_param_never_eq(params,
-                                                 SND_PCM_HW_PARAM_FORMAT,
-                                                 sparams));
-               
-       channels_always = snd_pcm_hw_param_always_eq(params,
-                                                    SND_PCM_HW_PARAM_CHANNELS,
-                                                    sparams);
-       channels_never = (!channels_always &&
-                         snd_pcm_hw_param_never_eq(params,
-                                                   SND_PCM_HW_PARAM_CHANNELS,
-                                                   sparams));
-               
-       rate_always = snd_pcm_hw_param_always_eq(params,
-                                                SND_PCM_HW_PARAM_RATE,
-                                                sparams);
-       rate_never = (!rate_always &&
-                     snd_pcm_hw_param_never_eq(params,
-                                               SND_PCM_HW_PARAM_RATE,
-                                               sparams));
-
-       if (rate_always)
-               links |= (SND_PCM_HW_PARBIT_RATE |
-                         SND_PCM_HW_PARBIT_PERIOD_SIZE |
-                         SND_PCM_HW_PARBIT_PERIODS |
-                         SND_PCM_HW_PARBIT_BUFFER_TIME |
-                         SND_PCM_HW_PARBIT_BUFFER_SIZE);
-       else {
-               interval_t t;
-               const interval_t *sbuffer_size, *buffer_size;
-               const interval_t *srate, *rate;
-               buffer_size = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE);
-               sbuffer_size = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE);
-               rate = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_RATE);
-               srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE);
-               interval_muldiv(sbuffer_size, rate, srate, &t);
-               interval_round(&t);
-               err = _snd_pcm_hw_param_refine_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
-               if (err < 0)
-                       return err;
-               interval_muldiv(buffer_size, srate, rate, &t);
-               interval_round(&t);
-               err = _snd_pcm_hw_param_refine_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
-               assert(err >= 0);
-               scmask |= sparams->cmask;
-       }
-       if (channels_always)
-               links |= SND_PCM_HW_PARBIT_CHANNELS;
-       if (format_always) {
-               links |= (SND_PCM_HW_PARBIT_FORMAT |
-                         SND_PCM_HW_PARBIT_SUBFORMAT |
-                         SND_PCM_HW_PARBIT_SAMPLE_BITS);
-               if (channels_always) {
-                       links |= SND_PCM_HW_PARBIT_FRAME_BITS;
-                       if (rate_always) 
-                               links |= (SND_PCM_HW_PARBIT_PERIOD_BYTES |
-                                         SND_PCM_HW_PARBIT_BUFFER_BYTES);
-               }
-       }
-
-       mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
-       if (format_never || channels_never || rate_never) {
-               mask_t *mmap_mask = alloca(mask_sizeof());
-               mask_load(mmap_mask, SND_PCM_ACCBIT_MMAP);
-               err = _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
-                                            mmap_mask);
-               assert(err >= 0);
-       } else
-               mask_union(access_mask, snd_pcm_hw_param_value_mask(sparams, SND_PCM_HW_PARAM_ACCESS));
-       err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
-                                    access_mask);
-       if (err < 0)
-               return err;
-       sparams->cmask |= scmask;
-       return snd_pcm_generic_hw_link(params, sparams, slave, links);
-}
-
-static int snd_pcm_plug_hw_refine1(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
-                                  snd_pcm_hw_params_t *sparams)
-{
-       snd_pcm_plug_t *plug = pcm->private;
-       snd_pcm_t *slave = plug->req_slave;
-       unsigned int cmask, lcmask;
-       int err;
-       
-       cmask = params->cmask;
-       params->cmask = 0;
-       err = _snd_pcm_hw_param_min(params, SND_PCM_HW_PARAM_CHANNELS, 1, 0);
-       if (err < 0)
-               return err;
-       err = _snd_pcm_hw_param_max(params, SND_PCM_HW_PARAM_CHANNELS, 1024, 0);
-       if (err < 0)
-               return err;
-       err = _snd_pcm_hw_param_min(params, SND_PCM_HW_PARAM_RATE, RATE_MIN, 0);
-       if (err < 0)
-               return err;
-       err = _snd_pcm_hw_param_max(params, SND_PCM_HW_PARAM_RATE, RATE_MAX, 0);
-       if (err < 0)
-               return err;
-       lcmask = params->cmask;
-       params->cmask |= cmask;
-
-       _snd_pcm_hw_params_any(sparams);
-       err = snd_pcm_hw_refine2(params, sparams,
-                                snd_pcm_plug_hw_link, slave, 0);
-       params->cmask |= lcmask;
-       if (err < 0)
-               return err;
-       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       return 0;
-}
-
-
-
-static int snd_pcm_plug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
-{
-       snd_pcm_hw_params_t sparams;
-       return snd_pcm_plug_hw_refine1(pcm, params, &sparams);
-}
-
 static void snd_pcm_plug_clear(snd_pcm_t *pcm)
 {
        snd_pcm_plug_t *plug = pcm->private;
@@ -580,13 +404,164 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
        return 0;
 }
 
+static int snd_pcm_plug_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED)
+{
+       return 0;
+}
+
+static int snd_pcm_plug_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams)
+{
+       snd_pcm_plug_t *plug = pcm->private;
+       snd_pcm_t *slave = plug->req_slave;
+       return snd_pcm_hw_params_any(slave, sparams);
+}
+
+static int snd_pcm_plug_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                                         snd_pcm_hw_params_t *sparams)
+{
+       snd_pcm_plug_t *plug = pcm->private;
+       snd_pcm_t *slave = plug->req_slave;
+       unsigned int links = (SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       const mask_t *format_mask, *sformat_mask;
+       mask_t *sfmt_mask = alloca(mask_sizeof());
+       int err;
+       unsigned int format;
+       interval_t t;
+       const interval_t *buffer_size;
+       const interval_t *srate, *crate;
+       err = _snd_pcm_hw_params_refine(sparams, links, params);
+       if (err < 0)
+               return err;
+       snd_pcm_hw_param_refine_near(slave, sparams, SND_PCM_HW_PARAM_RATE,
+                                    params);
+       snd_pcm_hw_param_refine_near(slave, sparams, SND_PCM_HW_PARAM_CHANNELS,
+                                    params);
+       format_mask = snd_pcm_hw_param_value_mask(params,
+                                                  SND_PCM_HW_PARAM_FORMAT);
+       sformat_mask = snd_pcm_hw_param_value_mask(sparams,
+                                                   SND_PCM_HW_PARAM_FORMAT);
+       mask_none(sfmt_mask);
+       for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
+               int f;
+               if (!mask_test(format_mask, format))
+                       continue;
+               if (mask_test(sformat_mask, format))
+                       f = format;
+               else {
+                       f = snd_pcm_plug_slave_format(format, sformat_mask);
+                       if (f < 0)
+                               continue;
+               }
+               mask_set(sfmt_mask, f);
+       }
+
+       err = snd_pcm_hw_param_mask(slave, sparams,
+                                   SND_PCM_HW_PARAM_FORMAT, sfmt_mask);
+       assert(err >= 0);
+
+       if (snd_pcm_hw_param_never_eq(params, SND_PCM_HW_PARAM_FORMAT, sparams) ||
+           snd_pcm_hw_param_never_eq(params, SND_PCM_HW_PARAM_CHANNELS, sparams) ||
+           snd_pcm_hw_param_never_eq(params, SND_PCM_HW_PARAM_RATE, sparams) ||
+           snd_pcm_hw_param_never_eq(params, SND_PCM_HW_PARAM_ACCESS, sparams)) {
+               mask_t *access_mask = alloca(mask_sizeof());
+               mask_load(access_mask, SND_PCM_ACCBIT_MMAP);
+               _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
+                                      access_mask);
+       }
+       buffer_size = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE);
+       crate = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_RATE);
+       srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE);
+       interval_muldiv(buffer_size, srate, crate, &t);
+       interval_round(&t);
+       err = _snd_pcm_hw_param_refine_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
+       if (err < 0)
+               return err;
+       return 0;
+}
+       
+static int snd_pcm_plug_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
+                                         snd_pcm_hw_params_t *params,
+                                         snd_pcm_hw_params_t *sparams)
+{
+       unsigned int links = (SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       const mask_t *format_mask, *sformat_mask;
+       mask_t *fmt_mask = alloca(mask_sizeof());
+       int err;
+       unsigned int format;
+       interval_t t;
+       const interval_t *sbuffer_size;
+       const interval_t *srate, *crate;
+       format_mask = snd_pcm_hw_param_value_mask(params,
+                                                  SND_PCM_HW_PARAM_FORMAT);
+       sformat_mask = snd_pcm_hw_param_value_mask(sparams,
+                                                   SND_PCM_HW_PARAM_FORMAT);
+       mask_none(fmt_mask);
+       for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
+               int f;
+               if (!mask_test(format_mask, format))
+                       continue;
+               if (mask_test(sformat_mask, format))
+                       f = format;
+               else {
+                       f = snd_pcm_plug_slave_format(format, sformat_mask);
+                       if (f < 0)
+                               continue;
+               }
+               mask_set(fmt_mask, format);
+       }
+
+       err = _snd_pcm_hw_param_mask(params, 
+                                    SND_PCM_HW_PARAM_FORMAT, fmt_mask);
+       if (err < 0)
+               return err;
+
+       sbuffer_size = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE);
+       crate = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_RATE);
+       srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE);
+       interval_muldiv(sbuffer_size, crate, srate, &t);
+       interval_round(&t);
+       err = _snd_pcm_hw_param_refine_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_refine(params, links, sparams);
+       if (err < 0)
+               return err;
+       /* FIXME */
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       return 0;
+}
+
+static int snd_pcm_plug_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       snd_pcm_plug_t *plug = pcm->private;
+       return snd_pcm_hw_refine(plug->req_slave, params);
+}
+
+static int snd_pcm_plug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       return snd_pcm_hw_refine_slave(pcm, params,
+                                      snd_pcm_plug_hw_refine_cprepare,
+                                      snd_pcm_plug_hw_refine_cchange,
+                                      snd_pcm_plug_hw_refine_sprepare,
+                                      snd_pcm_plug_hw_refine_schange,
+                                      snd_pcm_plug_hw_refine_slave);
+}
+
 static int snd_pcm_plug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_plug_t *plug = pcm->private;
        snd_pcm_t *slave = plug->req_slave;
        snd_pcm_plug_params_t clt_params, slv_params;
        snd_pcm_hw_params_t sparams;
-       int err = snd_pcm_plug_hw_refine1(pcm, params, &sparams);
+       int err;
+
+       err = snd_pcm_plug_hw_refine_sprepare(pcm, &sparams);
+       assert(err >= 0);
+       err = snd_pcm_plug_hw_refine_schange(pcm, params, &sparams);
+       assert(err >= 0);
+       err = snd_pcm_hw_refine_soft(slave, &sparams);
        assert(err >= 0);
 
        clt_params.access = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_ACCESS, 0);
@@ -594,21 +569,14 @@ static int snd_pcm_plug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
        clt_params.channels = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_CHANNELS, 0);
        clt_params.rate = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_RATE, 0);
 
+       slv_params.access = snd_pcm_hw_param_first(slave, &sparams, SND_PCM_HW_PARAM_ACCESS, 0);
        slv_params.format = snd_pcm_hw_param_value(&sparams, SND_PCM_HW_PARAM_FORMAT, 0);
        slv_params.channels = snd_pcm_hw_param_value(&sparams, SND_PCM_HW_PARAM_CHANNELS, 0);
        slv_params.rate = snd_pcm_hw_param_value(&sparams, SND_PCM_HW_PARAM_RATE, 0);
        snd_pcm_plug_clear(pcm);
-       if (clt_params.format == slv_params.format &&
-           clt_params.channels == slv_params.channels &&
-           clt_params.rate == slv_params.rate &&
-           snd_pcm_hw_param_test(params, SND_PCM_HW_PARAM_ACCESS, clt_params.access))
-               slv_params.access = clt_params.access;
-       else {
-               slv_params.access = snd_pcm_hw_param_first(slave, &sparams, SND_PCM_HW_PARAM_ACCESS, 0);
-               err = snd_pcm_plug_insert_plugins(pcm, &clt_params, &slv_params);
-               if (err < 0)
-                       return err;
-       }
+       err = snd_pcm_plug_insert_plugins(pcm, &clt_params, &slv_params);
+       if (err < 0)
+               return err;
        err = snd_pcm_hw_params(plug->slave, params);
        if (err < 0) {
                snd_pcm_plug_clear(pcm);
index f98d08f..78eb558 100644 (file)
@@ -340,6 +340,18 @@ int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm)
        return snd_pcm_poll_descriptor(plugin->slave);
 }
 
+int snd_pcm_plugin_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       snd_pcm_plugin_t *plugin = pcm->private;
+       return snd_pcm_hw_refine(plugin->slave, params);
+}
+
+int snd_pcm_plugin_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       snd_pcm_plugin_t *plugin = pcm->private;
+       return snd_pcm_hw_params(plugin->slave, params);
+}
+
 int conv_index(int src_format, int dst_format)
 {
        int src_endian, dst_endian, sign, src_width, dst_width;
index ef72335..62f75dd 100644 (file)
@@ -64,6 +64,8 @@ int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm);
 int get_index(int src_format, int dst_format);
 int put_index(int src_format, int dst_format);
 int conv_index(int src_format, int dst_format);
+int snd_pcm_plugin_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
+int snd_pcm_plugin_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
 
 #define SND_PCM_FMTBIT_LINEAR \
        ((1 << SND_PCM_FORMAT_S8    ) | (1 << SND_PCM_FORMAT_U8) | \
index aacdf34..d793be9 100644 (file)
@@ -23,6 +23,7 @@
 #include <byteswap.h>
 #include "pcm_local.h"
 #include "pcm_plugin.h"
+#include "interval.h"
 
 #define DIV (1<<16)
 
@@ -233,30 +234,23 @@ static int snd_pcm_rate_close(snd_pcm_t *pcm)
        return 0;
 }
 
-static int snd_pcm_rate_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+static int snd_pcm_rate_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
 {
-       snd_pcm_rate_t *rate = pcm->private;
-       snd_pcm_t *slave = rate->plug.slave;
        int err;
-       unsigned int cmask, lcmask;
-       snd_pcm_hw_params_t sparams;
-       unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
-                             SND_PCM_HW_PARBIT_PERIOD_TIME |
-                             SND_PCM_HW_PARBIT_TICK_TIME);
        mask_t *access_mask = alloca(mask_sizeof());
        mask_t *format_mask = alloca(mask_sizeof());
-       mask_t *saccess_mask = alloca(mask_sizeof());
        mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
        mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-       cmask = params->cmask;
-       params->cmask = 0;
        err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
-                                     access_mask);
+                                    access_mask);
        if (err < 0)
                return err;
        err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT,
-                                     format_mask);
+                                    format_mask);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
+                                    SND_PCM_SUBFORMAT_STD, 0);
        if (err < 0)
                return err;
        err = _snd_pcm_hw_param_min(params,
@@ -267,81 +261,114 @@ static int snd_pcm_rate_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
                                     SND_PCM_HW_PARAM_RATE, RATE_MAX, 0);
        if (err < 0)
                return err;
-       lcmask = params->cmask;
-       params->cmask |= cmask;
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       return 0;
+}
 
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
+static int snd_pcm_rate_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
+{
+       snd_pcm_rate_t *rate = pcm->private;
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       _snd_pcm_hw_params_any(sparams);
+       _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
                                saccess_mask);
-       snd_pcm_hw_param_near_copy(slave, &sparams,
-                                  SND_PCM_HW_PARAM_BUFFER_TIME,
-                                  params);
        if (rate->sformat >= 0) {
-               _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
+               _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_FORMAT,
                                      rate->sformat, 0);
-               _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
+               _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_SUBFORMAT,
                                      SND_PCM_SUBFORMAT_STD, 0);
-       } else
+       }
+       _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_RATE,
+                             rate->srate, 0);
+       return 0;
+}
+
+static int snd_pcm_rate_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                                         snd_pcm_hw_params_t *sparams)
+{
+       snd_pcm_rate_t *rate = pcm->private;
+       interval_t t;
+       const interval_t *buffer_size;
+       const interval_t *srate, *crate;
+       int err;
+       unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+                             SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       if (rate->sformat < 0)
                links |= (SND_PCM_HW_PARBIT_FORMAT |
                          SND_PCM_HW_PARBIT_SUBFORMAT |
                          SND_PCM_HW_PARBIT_SAMPLE_BITS |
                          SND_PCM_HW_PARBIT_FRAME_BITS);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_RATE,
-                             rate->srate, 0);
-               
-       err = snd_pcm_hw_refine2(params, &sparams,
-                                snd_pcm_generic_hw_link, slave, links);
-       params->cmask |= lcmask;
+       buffer_size = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE);
+       crate = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_RATE);
+       srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE);
+       interval_muldiv(buffer_size, srate, crate, &t);
+       interval_round(&t);
+       err = _snd_pcm_hw_param_refine_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_refine(sparams, links, params);
        if (err < 0)
                return err;
-       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        return 0;
 }
-
-static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
+       
+static int snd_pcm_rate_hw_refine_cchange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                                         snd_pcm_hw_params_t *sparams)
 {
        snd_pcm_rate_t *rate = pcm->private;
-       snd_pcm_t *slave = rate->plug.slave;
+       interval_t t;
+       const interval_t *sbuffer_size;
+       const interval_t *srate, *crate;
        int err;
-       snd_pcm_hw_params_t sparams;
        unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
                              SND_PCM_HW_PARBIT_PERIOD_TIME |
                              SND_PCM_HW_PARBIT_TICK_TIME);
-       unsigned int src_format, dst_format;
-       unsigned int src_rate, dst_rate;
-       mask_t *saccess_mask = alloca(mask_sizeof());
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                               saccess_mask);
-       if (rate->sformat >= 0) {
-               _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
-                                     rate->sformat, 0);
-               _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
-                                     SND_PCM_SUBFORMAT_STD, 0);
-       } else
+       if (rate->sformat < 0)
                links |= (SND_PCM_HW_PARBIT_FORMAT |
                          SND_PCM_HW_PARBIT_SUBFORMAT |
                          SND_PCM_HW_PARBIT_SAMPLE_BITS |
                          SND_PCM_HW_PARBIT_FRAME_BITS);
+       sbuffer_size = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_BUFFER_SIZE);
+       crate = snd_pcm_hw_param_value_interval(params, SND_PCM_HW_PARAM_RATE);
+       srate = snd_pcm_hw_param_value_interval(sparams, SND_PCM_HW_PARAM_RATE);
+       interval_muldiv(sbuffer_size, crate, srate, &t);
+       interval_round(&t);
+       err = _snd_pcm_hw_param_refine_interval(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &t);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_refine(params, links, sparams);
+       if (err < 0)
+               return err;
+       return 0;
+}
 
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_RATE,
-                             rate->srate, 0);
+static int snd_pcm_rate_hw_refine(snd_pcm_t *pcm, 
+                                 snd_pcm_hw_params_t *params)
+{
+       return snd_pcm_hw_refine_slave(pcm, params,
+                                      snd_pcm_rate_hw_refine_cprepare,
+                                      snd_pcm_rate_hw_refine_cchange,
+                                      snd_pcm_rate_hw_refine_sprepare,
+                                      snd_pcm_rate_hw_refine_schange,
+                                      snd_pcm_plugin_hw_refine_slave);
+}
 
-       snd_pcm_hw_param_near_copy(slave, &sparams,
-                                  SND_PCM_HW_PARAM_BUFFER_TIME,
-                                  params);
-               
-       err = snd_pcm_hw_params_refine(&sparams, links, params);
-       assert(err >= 0);
-       err = snd_pcm_hw_params(slave, &sparams);
-       params->cmask = 0;
-       sparams.cmask = ~0U;
-       snd_pcm_hw_params_refine(params, links, &sparams);
+static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
+{
+       snd_pcm_rate_t *rate = pcm->private;
+       snd_pcm_t *slave = rate->plug.slave;
+       unsigned int src_format, dst_format;
+       unsigned int src_rate, dst_rate;
+       int err = snd_pcm_hw_params_slave(pcm, params,
+                                         snd_pcm_rate_hw_refine_cchange,
+                                         snd_pcm_rate_hw_refine_sprepare,
+                                         snd_pcm_rate_hw_refine_schange,
+                                         snd_pcm_plugin_hw_params_slave);
        if (err < 0)
                return err;
-       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
                src_format = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0);
                dst_format = slave->format;
index 01b209e..afe6ce5 100644 (file)
@@ -425,80 +425,82 @@ static int snd_pcm_route_close(snd_pcm_t *pcm)
        return 0;
 }
 
-static int snd_pcm_route_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+static int snd_pcm_route_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
 {
-       snd_pcm_route_t *route = pcm->private;
-       snd_pcm_t *slave = route->plug.slave;
        int err;
-       unsigned int cmask, lcmask;
-       snd_pcm_hw_params_t sparams;
-       unsigned int links = (SND_PCM_HW_PARBIT_RATE |
-                             SND_PCM_HW_PARBIT_PERIODS |
-                             SND_PCM_HW_PARBIT_PERIOD_SIZE |
-                             SND_PCM_HW_PARBIT_PERIOD_TIME |
-                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
-                             SND_PCM_HW_PARBIT_BUFFER_TIME |
-                             SND_PCM_HW_PARBIT_TICK_TIME);
        mask_t *access_mask = alloca(mask_sizeof());
        mask_t *format_mask = alloca(mask_sizeof());
-       mask_t *saccess_mask = alloca(mask_sizeof());
        mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
        mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-       cmask = params->cmask;
-       params->cmask = 0;
        err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
-                                     access_mask);
+                                    access_mask);
        if (err < 0)
                return err;
        err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_FORMAT,
-                                     format_mask);
+                                    format_mask);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_SUBFORMAT,
+                                    SND_PCM_SUBFORMAT_STD, 0);
        if (err < 0)
                return err;
        err = _snd_pcm_hw_param_min(params, SND_PCM_HW_PARAM_CHANNELS, 1, 0);
        if (err < 0)
                return err;
-       lcmask = params->cmask;
-       params->cmask |= cmask;
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       return 0;
+}
 
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
+static int snd_pcm_route_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
+{
+       snd_pcm_route_t *route = pcm->private;
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       _snd_pcm_hw_params_any(sparams);
+       _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
                                saccess_mask);
        if (route->sformat >= 0) {
-               _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
+               _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_FORMAT,
                                      route->sformat, 0);
-               _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
+               _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_SUBFORMAT,
                                      SND_PCM_SUBFORMAT_STD, 0);
-       } else
+       }
+       if (route->schannels >= 0) {
+               _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS,
+                                     route->schannels, 0);
+       }
+       return 0;
+}
+
+static int snd_pcm_route_hw_refine_schange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                                           snd_pcm_hw_params_t *sparams)
+{
+       snd_pcm_route_t *route = pcm->private;
+       int err;
+       unsigned int links = (SND_PCM_HW_PARBIT_RATE |
+                             SND_PCM_HW_PARBIT_PERIODS |
+                             SND_PCM_HW_PARBIT_PERIOD_SIZE |
+                             SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_TIME |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       if (route->sformat < 0)
                links |= (SND_PCM_HW_PARBIT_FORMAT | 
                          SND_PCM_HW_PARBIT_SUBFORMAT |
                          SND_PCM_HW_PARBIT_SAMPLE_BITS);
-       if (route->schannels >= 0) {
-               _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_CHANNELS,
-                                     route->schannels, 0);
-       } else {
+       if (route->schannels < 0)
                links |= SND_PCM_HW_PARBIT_CHANNELS;
-               if (route->sformat < 0)
-                       links |= (SND_PCM_HW_PARBIT_FRAME_BITS |
-                                 SND_PCM_HW_PARBIT_PERIOD_BYTES |
-                                 SND_PCM_HW_PARBIT_BUFFER_BYTES);
-       }
-               
-       err = snd_pcm_hw_refine2(params, &sparams,
-                                snd_pcm_generic_hw_link, slave, links);
-       params->cmask |= lcmask;
+       err = _snd_pcm_hw_params_refine(sparams, links, params);
        if (err < 0)
                return err;
-       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        return 0;
 }
-
-static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
+       
+static int snd_pcm_route_hw_refine_cchange(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                                           snd_pcm_hw_params_t *sparams)
 {
        snd_pcm_route_t *route = pcm->private;
-       snd_pcm_t *slave = route->plug.slave;
        int err;
-       snd_pcm_hw_params_t sparams;
        unsigned int links = (SND_PCM_HW_PARBIT_RATE |
                              SND_PCM_HW_PARBIT_PERIODS |
                              SND_PCM_HW_PARBIT_PERIOD_SIZE |
@@ -506,42 +508,41 @@ static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
                              SND_PCM_HW_PARBIT_BUFFER_SIZE |
                              SND_PCM_HW_PARBIT_BUFFER_TIME |
                              SND_PCM_HW_PARBIT_TICK_TIME);
-       unsigned int src_format, dst_format;
-       mask_t *saccess_mask = alloca(mask_sizeof());
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                               saccess_mask);
-       if (route->sformat >= 0) {
-               _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_FORMAT,
-                                     route->sformat, 0);
-               _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_SUBFORMAT,
-                                     SND_PCM_SUBFORMAT_STD, 0);
-       } else
+       if (route->sformat < 0)
                links |= (SND_PCM_HW_PARBIT_FORMAT | 
                          SND_PCM_HW_PARBIT_SUBFORMAT |
                          SND_PCM_HW_PARBIT_SAMPLE_BITS);
-       if (route->schannels >= 0) {
-               _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_CHANNELS,
-                                     route->schannels, 0);
-       } else {
+       if (route->schannels < 0)
                links |= SND_PCM_HW_PARBIT_CHANNELS;
-               if (route->sformat < 0)
-                       links |= (SND_PCM_HW_PARBIT_FRAME_BITS |
-                                 SND_PCM_HW_PARBIT_PERIOD_BYTES |
-                                 SND_PCM_HW_PARBIT_BUFFER_BYTES);
-       }
+       err = _snd_pcm_hw_params_refine(params, links, sparams);
+       if (err < 0)
+               return err;
+       return 0;
+}
 
-       err = snd_pcm_hw_params_refine(&sparams, links, params);
-       assert(err >= 0);
-       err = snd_pcm_hw_params(slave, &sparams);
-       params->cmask = 0;
-       sparams.cmask = ~0U;
-       snd_pcm_hw_params_refine(params, links, &sparams);
+static int snd_pcm_route_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       return snd_pcm_hw_refine_slave(pcm, params,
+                                      snd_pcm_route_hw_refine_cprepare,
+                                      snd_pcm_route_hw_refine_cchange,
+                                      snd_pcm_route_hw_refine_sprepare,
+                                      snd_pcm_route_hw_refine_schange,
+                                      snd_pcm_plugin_hw_refine_slave);
+}
+
+static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
+{
+       snd_pcm_route_t *route = pcm->private;
+       snd_pcm_t *slave = route->plug.slave;
+       unsigned int src_format, dst_format;
+       int err = snd_pcm_hw_params_slave(pcm, params,
+                                         snd_pcm_route_hw_refine_cchange,
+                                         snd_pcm_route_hw_refine_sprepare,
+                                         snd_pcm_route_hw_refine_schange,
+                                         snd_pcm_plugin_hw_params_slave);
        if (err < 0)
                return err;
-       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
                src_format = snd_pcm_hw_param_value(params, SND_PCM_HW_PARAM_FORMAT, 0);
                dst_format = slave->format;
index eb67950..57c3e57 100644 (file)
@@ -427,7 +427,8 @@ static void _snd_pcm_share_update(snd_pcm_t *pcm)
 
 static int snd_pcm_share_card(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 {
-       return -ENOENT; /* not available */
+       snd_pcm_share_t *share = pcm->private;
+       return snd_pcm_card(share->slave->pcm);
 }
 
 static int snd_pcm_share_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
@@ -455,25 +456,22 @@ static int snd_pcm_share_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
        return snd_pcm_info(share->slave->pcm, info);
 }
 
-static int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+static int snd_pcm_share_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_share_t *share = pcm->private;
        snd_pcm_share_slave_t *slave = share->slave;
-       snd_pcm_hw_params_t sparams;
-       int err;
-       unsigned int cmask, lcmask;
        mask_t *access_mask = alloca(mask_sizeof());
-       const mask_t *mmap_mask;
-       mask_t *saccess_mask = alloca(mask_sizeof());
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-
-       cmask = params->cmask;
-       params->cmask = 0;
+       int err;
+       mask_any(access_mask);
+       mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+       err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
+                                    access_mask);
+       if (err < 0)
+               return err;
        err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS,
                                    share->channels_count, 0);
        if (err < 0)
                return err;
-
        if (slave->format >= 0) {
                err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_FORMAT,
                                            slave->format, 0);
@@ -487,44 +485,109 @@ static int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
                if (err < 0)
                        return err;
        }
-       lcmask = params->cmask;
-       params->cmask |= cmask;
+       params->info |= SND_PCM_INFO_DOUBLE;
+       return 0;
+}
 
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
+static int snd_pcm_share_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
+{
+       snd_pcm_share_t *share = pcm->private;
+       snd_pcm_share_slave_t *slave = share->slave;
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       _snd_pcm_hw_params_any(sparams);
+       _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
                               saccess_mask);
-       _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_CHANNELS,
+       _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS,
                              slave->channels_count, 0);
-       err = snd_pcm_hw_refine2(params, &sparams,
-                                snd_pcm_generic_hw_link, slave->pcm,
-                                SND_PCM_HW_PARBIT_FORMAT |
-                                SND_PCM_HW_PARBIT_SUBFORMAT |
-                                SND_PCM_HW_PARBIT_RATE |
-                                SND_PCM_HW_PARBIT_PERIOD_SIZE |
-                                SND_PCM_HW_PARBIT_PERIOD_TIME |
-                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
-                                SND_PCM_HW_PARBIT_BUFFER_TIME |
-                                SND_PCM_HW_PARBIT_PERIODS |
-                                SND_PCM_HW_PARBIT_TICK_TIME);
+       return 0;
+}
+
+static int snd_pcm_share_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+                                         snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = (SND_PCM_HW_PARBIT_FORMAT |
+                             SND_PCM_HW_PARBIT_SUBFORMAT |
+                             SND_PCM_HW_PARBIT_RATE |
+                             SND_PCM_HW_PARBIT_PERIOD_SIZE |
+                             SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_TIME |
+                             SND_PCM_HW_PARBIT_PERIODS |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
+       if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
+           !mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) &&
+           !mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) {
+               mask_t *saccess_mask = alloca(mask_sizeof());
+               mask_any(saccess_mask);
+               mask_reset(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+               err = _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
+                                            saccess_mask);
+               if (err < 0)
+                       return err;
+       }
+       err = _snd_pcm_hw_params_refine(sparams, links, params);
        if (err < 0)
                return err;
-       mmap_mask = snd_pcm_hw_param_value_mask(&sparams, SND_PCM_HW_PARAM_ACCESS);
+       return 0;
+}
+       
+static int snd_pcm_share_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+                                          snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = (SND_PCM_HW_PARBIT_FORMAT |
+                             SND_PCM_HW_PARBIT_SUBFORMAT |
+                             SND_PCM_HW_PARBIT_RATE |
+                             SND_PCM_HW_PARBIT_PERIOD_SIZE |
+                             SND_PCM_HW_PARBIT_PERIOD_TIME |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_TIME |
+                             SND_PCM_HW_PARBIT_PERIODS |
+                             SND_PCM_HW_PARBIT_TICK_TIME);
+       mask_t *access_mask = alloca(mask_sizeof());
+       const mask_t *saccess_mask = snd_pcm_hw_param_value_mask(sparams, SND_PCM_HW_PARAM_ACCESS);
        mask_any(access_mask);
        mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
-       if (!mask_test(mmap_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
+       if (!mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
                mask_reset(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
-       if (!mask_test(mmap_mask, SND_PCM_ACCESS_MMAP_COMPLEX) &&
-           !mask_test(mmap_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED))
+       if (!mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX) &&
+           !mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED))
                mask_reset(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
        err = _snd_pcm_hw_param_mask(params, SND_PCM_HW_PARAM_ACCESS,
-                                     access_mask);
-       params->cmask |= lcmask;
+                                    access_mask);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_refine(params, links, sparams);
        if (err < 0)
                return err;
-       params->info |= SND_PCM_INFO_DOUBLE;
        return 0;
 }
 
+static int snd_pcm_share_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       snd_pcm_share_t *share = pcm->private;
+       return snd_pcm_hw_refine(share->slave->pcm, params);
+}
+
+static int snd_pcm_share_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       snd_pcm_share_t *share = pcm->private;
+       return snd_pcm_hw_params(share->slave->pcm, params);
+}
+
+static int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       return snd_pcm_hw_refine_slave(pcm, params,
+                                      snd_pcm_share_hw_refine_cprepare,
+                                      snd_pcm_share_hw_refine_cchange,
+                                      snd_pcm_share_hw_refine_sprepare,
+                                      snd_pcm_share_hw_refine_schange,
+                                      snd_pcm_share_hw_refine_slave);
+}
+
 static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_share_t *share = pcm->private;
@@ -534,7 +597,6 @@ static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
        Pthread_mutex_lock(&slave->mutex);
        if (slave->setup_count > 1 || 
            (slave->setup_count == 1 && !pcm->setup)) {
-               params->cmask = 0;
                err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_FORMAT,
                                            spcm->format, 0);
                if (err < 0)
@@ -564,30 +626,11 @@ static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
                        goto _end;
                }
        } else {
-               snd_pcm_hw_params_t sparams;
-               unsigned int links;
-               mask_t *saccess_mask = alloca(mask_sizeof());
-               mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-               links = SND_PCM_HW_PARBIT_FORMAT |
-                       SND_PCM_HW_PARBIT_SUBFORMAT |
-                       SND_PCM_HW_PARBIT_RATE |
-                       SND_PCM_HW_PARBIT_PERIOD_SIZE |
-                       SND_PCM_HW_PARBIT_PERIOD_TIME |
-                       SND_PCM_HW_PARBIT_BUFFER_SIZE |
-                       SND_PCM_HW_PARBIT_BUFFER_TIME |
-                       SND_PCM_HW_PARBIT_PERIODS |
-                       SND_PCM_HW_PARBIT_TICK_TIME;
-               _snd_pcm_hw_params_any(&sparams);
-               _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                                      saccess_mask);
-               _snd_pcm_hw_param_set(&sparams, SND_PCM_HW_PARAM_CHANNELS,
-                                     share->channels_count, 0);
-               err = snd_pcm_hw_params_refine(&sparams, links, params);
-               assert(err >= 0);
-               err = snd_pcm_hw_params(slave->pcm, &sparams);
-               params->cmask = 0;
-               sparams.cmask = ~0U;
-               snd_pcm_hw_params_refine(params, links, &sparams);
+               err = snd_pcm_hw_params_slave(pcm, params,
+                                             snd_pcm_share_hw_refine_cchange,
+                                             snd_pcm_share_hw_refine_sprepare,
+                                             snd_pcm_share_hw_refine_schange,
+                                             snd_pcm_share_hw_params_slave);
                if (err < 0)
                        goto _end;
                snd_pcm_sw_params_current(slave->pcm, &slave->sw_params);
index 65e4e6f..b895bde 100644 (file)
@@ -155,8 +155,61 @@ static int snd_pcm_shm_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
        return err;
 }
 
-static int _snd_pcm_shm_hw_refine(snd_pcm_t *pcm,
-                                 snd_pcm_hw_params_t *params)
+static int snd_pcm_shm_hw_refine_cprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED)
+{
+       return 0;
+}
+
+static int snd_pcm_shm_hw_refine_sprepare(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *sparams)
+{
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       _snd_pcm_hw_params_any(sparams);
+       _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
+                              saccess_mask);
+       return 0;
+}
+
+static int snd_pcm_shm_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+                                         snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS;
+       const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
+       if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
+           !mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) {
+               err = _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
+                                            access_mask);
+               if (err < 0)
+                       return err;
+       }
+       err = _snd_pcm_hw_params_refine(sparams, links, params);
+       if (err < 0)
+               return err;
+       return 0;
+}
+       
+static int snd_pcm_shm_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
+                                         snd_pcm_hw_params_t *sparams)
+{
+       int err;
+       unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS;
+       mask_t *access_mask = alloca(mask_sizeof());
+       mask_copy(access_mask, snd_pcm_hw_param_value_mask(sparams, SND_PCM_HW_PARAM_ACCESS));
+       mask_set(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED);
+       mask_set(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED);
+       err = _snd_pcm_hw_param_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
+                                    access_mask);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_refine(params, links, sparams);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static int snd_pcm_shm_hw_refine_slave(snd_pcm_t *pcm,
+                                      snd_pcm_hw_params_t *params)
 {
        snd_pcm_shm_t *shm = pcm->private;
        volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
@@ -168,46 +221,18 @@ static int _snd_pcm_shm_hw_refine(snd_pcm_t *pcm,
        return err;
 }
 
-/* Accumulate to params->cmask */
-/* Reset sparams->cmask */
-int snd_pcm_shm_hw_link(snd_pcm_hw_params_t *params,
-                       snd_pcm_hw_params_t *sparams,
-                       snd_pcm_t *slave,
-                       unsigned long links)
-{
-       int err1, err = 0;
-       err = snd_pcm_hw_params_refine(sparams, links, params);
-       if (err >= 0) {
-               unsigned int cmask = sparams->cmask;
-               err = _snd_pcm_shm_hw_refine(slave, sparams);
-               sparams->cmask |= cmask;
-       }
-       err1 = snd_pcm_hw_params_refine(params, links, sparams);
-       if (err1 < 0)
-               err = err1;
-       sparams->cmask = 0;
-       return err;
-}
-
 static int snd_pcm_shm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
-       snd_pcm_hw_params_t sparams;
-       const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
-       mask_t *saccess_mask = alloca(mask_sizeof());
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-       if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
-           !mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
-               mask_intersect(saccess_mask, access_mask);
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                               saccess_mask);
-       return snd_pcm_hw_refine2(params, &sparams,
-                                 snd_pcm_shm_hw_link, pcm,
-                                 ~SND_PCM_HW_PARBIT_ACCESS);
+       return snd_pcm_hw_refine_slave(pcm, params,
+                                      snd_pcm_shm_hw_refine_cprepare,
+                                      snd_pcm_shm_hw_refine_cchange,
+                                      snd_pcm_shm_hw_refine_sprepare,
+                                      snd_pcm_shm_hw_refine_schange,
+                                      snd_pcm_shm_hw_refine_slave);
 }
 
-static int _snd_pcm_shm_hw_params(snd_pcm_t *pcm, 
-                                 snd_pcm_hw_params_t *params)
+static int snd_pcm_shm_hw_params_slave(snd_pcm_t *pcm, 
+                                      snd_pcm_hw_params_t *params)
 {
        snd_pcm_shm_t *shm = pcm->private;
        volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
@@ -221,27 +246,11 @@ static int _snd_pcm_shm_hw_params(snd_pcm_t *pcm,
 
 static int snd_pcm_shm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 {
-       snd_pcm_hw_params_t sparams;
-       unsigned int links = ~SND_PCM_HW_PARBIT_ACCESS;
-       const mask_t *access_mask = snd_pcm_hw_param_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
-       mask_t *saccess_mask = alloca(mask_sizeof());
-       int err;
-       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
-       if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
-           !mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
-               mask_intersect(saccess_mask, access_mask);
-       _snd_pcm_hw_params_any(&sparams);
-       _snd_pcm_hw_param_mask(&sparams, SND_PCM_HW_PARAM_ACCESS,
-                               saccess_mask);
-       err = snd_pcm_hw_params_refine(&sparams, links, params);
-       assert(err >= 0);
-       err = _snd_pcm_shm_hw_params(pcm, &sparams);
-       params->cmask = 0;
-       sparams.cmask = ~0U;
-       snd_pcm_hw_params_refine(params, links, &sparams);
-       if (err < 0)
-               return err;
-       return 0;
+       return snd_pcm_hw_params_slave(pcm, params,
+                                      snd_pcm_shm_hw_refine_cchange,
+                                      snd_pcm_shm_hw_refine_sprepare,
+                                      snd_pcm_shm_hw_refine_schange,
+                                      snd_pcm_shm_hw_params_slave);
 }
 
 static int snd_pcm_shm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)