OSDN Git Service

dmix - Allow more flexible buffer sizes
authorTakashi Iwai <tiwai@suse.de>
Tue, 21 Mar 2006 10:27:35 +0000 (10:27 +0000)
committerTakashi Iwai <tiwai@suse.de>
Tue, 21 Mar 2006 10:27:35 +0000 (10:27 +0000)
With the patch, dmix allows apps to use more flexible buffer sizes.
The max buffer size is unlimited, and the minimal buffer size is
(period size * 2).  The buffer size is aligned to period size.

The period size is still bound to the period size of slave PCM.

To back to the old behavior (the fixed buffer size), you can set

   defaults.pcm.dmix_variable_buffer false

in your configuration.

src/conf/alsa.conf
src/conf/pcm/dmix.conf
src/pcm/pcm_direct.c
src/pcm/pcm_direct.h
src/pcm/pcm_dmix.c
src/pcm/pcm_dshare.c
src/pcm/pcm_dsnoop.c

index ab5dcc1..a50037d 100644 (file)
@@ -57,6 +57,7 @@ defaults.pcm.nonblock 1
 defaults.pcm.ipc_key 5678293
 defaults.pcm.ipc_gid audio
 defaults.pcm.ipc_perm 0660
+defaults.pcm.dmix_variable_buffer true
 defaults.pcm.front.card defaults.pcm.card
 defaults.pcm.front.device defaults.pcm.device
 defaults.pcm.rear.card defaults.pcm.card
index 32700f2..5533450 100644 (file)
@@ -92,4 +92,9 @@ pcm.!dmix {
                        default 16
                }
        }
+       # Allow apps different buffer sizes
+       variable_buffer_size {
+               @func refer
+               name defaults.pcm.dmix_variable_buffer
+       }
 }
index 8be4d2a..22ac542 100644 (file)
@@ -632,6 +632,19 @@ static int hw_param_interval_refine_one(snd_pcm_hw_params_t *params,
        return 0;
 }
 
+static int hw_param_interval_refine_minmax(snd_pcm_hw_params_t *params,
+                                          snd_pcm_hw_param_t var,
+                                          unsigned int imin,
+                                          unsigned int imax)
+{
+       snd_interval_t t;
+
+       memset(&t, 0, sizeof(t));
+       snd_interval_set_minmax(&t, imin, imax);
+       t.integer = 1;
+       return hw_param_interval_refine_one(params, var, &t);
+}
+
 #undef REFINE_DEBUG
 
 int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
@@ -682,14 +695,6 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
                                           &dshare->shmptr->hw.rate);
        if (err < 0)
                return err;
-       err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE,
-                                          &dshare->shmptr->hw.buffer_size);
-       if (err < 0)
-               return err;
-       err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_TIME,
-                                          &dshare->shmptr->hw.buffer_time);
-       if (err < 0)
-               return err;
        err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE,
                                           &dshare->shmptr->hw.period_size);
        if (err < 0)
@@ -698,10 +703,33 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
                                           &dshare->shmptr->hw.period_time);
        if (err < 0)
                return err;
-       err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIODS,
-                                          &dshare->shmptr->hw.periods);
-       if (err < 0)
-               return err;
+       if (! dshare->variable_buffer_size) {
+               err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE,
+                                                  &dshare->shmptr->hw.buffer_size);
+               if (err < 0)
+                       return err;
+               err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_TIME,
+                                                  &dshare->shmptr->hw.buffer_time);
+               if (err < 0)
+                       return err;
+       } else if (params->rmask & ((1<<SND_PCM_HW_PARAM_PERIODS)|
+                                   (1<<SND_PCM_HW_PARAM_BUFFER_BYTES)|
+                                   (1<<SND_PCM_HW_PARAM_BUFFER_SIZE)|
+                                   (1<<SND_PCM_HW_PARAM_BUFFER_TIME))) {
+               int changed;
+               do {
+                       changed = 0;
+                       err = hw_param_interval_refine_minmax(params, SND_PCM_HW_PARAM_PERIODS,
+                                                     2, INT_MAX);
+                       if (err < 0)
+                               return err;
+                       changed |= err;
+                       err = snd_pcm_hw_refine_soft(pcm, params);
+                       if (err < 0)
+                               return err;
+                       changed |= err;
+               } while (changed);
+       }
        params->info = dshare->shmptr->s.info;
 #ifdef REFINE_DEBUG
        snd_output_puts(log, "DMIX REFINE (end):\n");
@@ -1376,6 +1404,7 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *conf, struct snd_pcm_direct_ope
        rec->ipc_perm = 0600;
        rec->ipc_gid = -1;
        rec->slowptr = 0;
+       rec->variable_buffer_size = 0;
 
        snd_config_for_each(i, next, conf) {
                snd_config_t *n = snd_config_iterator_entry(i);
@@ -1462,6 +1491,13 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *conf, struct snd_pcm_direct_ope
                        rec->slowptr = err;
                        continue;
                }
+               if (strcmp(id, "variable_buffer_size") == 0) {
+                       err = snd_config_get_bool(n);
+                       if (err < 0)
+                               return err;
+                       rec->variable_buffer_size = err;
+                       continue;
+               }
                SNDERR("Unknown field %s", id);
                return -EINVAL;
        }
index 31d3c4a..55fd787 100644 (file)
@@ -117,6 +117,7 @@ struct snd_pcm_direct {
        snd_timer_t *timer;             /* timer used as poll_fd */
        int interleaved;                /* we have interleaved buffer */
        int slowptr;                    /* use slow but more precise ptr updates */
+       int variable_buffer_size;       /* allow the variable buffer size */
        unsigned int channels;          /* client's channels */
        unsigned int *bindings;
        union {
@@ -196,6 +197,7 @@ struct snd_pcm_direct_open_conf {
        mode_t ipc_perm;
        int ipc_gid;
        int slowptr;
+       int variable_buffer_size;
        snd_config_t *slave;
        snd_config_t *bindings;
 };
index 5c00820..54706af 100644 (file)
@@ -760,12 +760,8 @@ static snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
  * \brief Creates a new dmix PCM
  * \param pcmp Returns created PCM handle
  * \param name Name of PCM
- * \param ipc_key IPC key for semaphore and shared memory
- * \param ipc_perm IPC permissions for semaphore and shared memory
- * \param ipc_gid IPC group ID for semaphore and shared memory
+ * \param opts Direct PCM configurations
  * \param params Parameters for slave
- * \param bindings Channel bindings
- * \param slowptr Slow but more precise pointer updates
  * \param root Configuration root
  * \param sconf Slave configuration
  * \param stream PCM Direction (stream)
@@ -776,10 +772,8 @@ static snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
  *          changed in future.
  */
 int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
-                     key_t ipc_key, mode_t ipc_perm, int ipc_gid,
+                     struct snd_pcm_direct_open_conf *opts,
                      struct slave_params *params,
-                     snd_config_t *bindings,
-                     int slowptr,
                      snd_config_t *root, snd_config_t *sconf,
                      snd_pcm_stream_t stream, int mode)
 {
@@ -801,13 +795,13 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
                goto _err_nosem;
        }
        
-       ret = snd_pcm_direct_parse_bindings(dmix, bindings);
+       ret = snd_pcm_direct_parse_bindings(dmix, opts->bindings);
        if (ret < 0)
                goto _err_nosem;
        
-       dmix->ipc_key = ipc_key;
-       dmix->ipc_perm = ipc_perm;
-       dmix->ipc_gid = ipc_gid;
+       dmix->ipc_key = opts->ipc_key;
+       dmix->ipc_perm = opts->ipc_perm;
+       dmix->ipc_gid = opts->ipc_gid;
        dmix->semid = -1;
        dmix->shmid = -1;
 
@@ -842,7 +836,8 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
        pcm->fast_ops = &snd_pcm_dmix_fast_ops;
        pcm->private_data = dmix;
        dmix->state = SND_PCM_STATE_OPEN;
-       dmix->slowptr = slowptr;
+       dmix->slowptr = opts->slowptr;
+       dmix->variable_buffer_size = opts->variable_buffer_size;
        dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
 
        if (first_instance) {
@@ -1132,8 +1127,7 @@ int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
        }
        dopen.ipc_key += ipc_offset;
 
-       err = snd_pcm_dmix_open(pcmp, name, dopen.ipc_key, dopen.ipc_perm, dopen.ipc_gid,
-                               &params, dopen.bindings, dopen.slowptr,
+       err = snd_pcm_dmix_open(pcmp, name, &dopen, &params,
                                root, sconf, stream, mode);
        if (err < 0)
                snd_config_delete(sconf);
index 31905fd..fd66573 100644 (file)
@@ -578,12 +578,8 @@ static snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = {
  * \brief Creates a new dshare PCM
  * \param pcmp Returns created PCM handle
  * \param name Name of PCM
- * \param ipc_key IPC key for semaphore and shared memory
- * \param ipc_perm IPC permissions for semaphore and shared memory
- * \param ipc_gid IPC group ID for semaphore and shared memory
+ * \param opts Direct PCM configurations
  * \param params Parameters for slave
- * \param bindings Channel bindings
- * \param slowptr Slow but more precise pointer updates
  * \param root Configuration root
  * \param sconf Slave configuration
  * \param stream PCM Direction (stream)
@@ -594,10 +590,8 @@ static snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = {
  *          changed in future.
  */
 int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
-                       key_t ipc_key, mode_t ipc_perm, int ipc_gid,
+                       struct snd_pcm_direct_open_conf *opts,
                        struct slave_params *params,
-                       snd_config_t *bindings,
-                       int slowptr,
                        snd_config_t *root, snd_config_t *sconf,
                        snd_pcm_stream_t stream, int mode)
 {
@@ -620,7 +614,7 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
                goto _err_nosem;
        }
        
-       ret = snd_pcm_direct_parse_bindings(dshare, bindings);
+       ret = snd_pcm_direct_parse_bindings(dshare, opts->bindings);
        if (ret < 0)
                goto _err_nosem;
                
@@ -630,9 +624,9 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
                goto _err_nosem;
        }
        
-       dshare->ipc_key = ipc_key;
-       dshare->ipc_perm = ipc_perm;
-       dshare->ipc_gid = ipc_gid;
+       dshare->ipc_key = opts->ipc_key;
+       dshare->ipc_perm = opts->ipc_perm;
+       dshare->ipc_gid = opts->ipc_gid;
        dshare->semid = -1;
        dshare->shmid = -1;
 
@@ -667,7 +661,8 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
        pcm->fast_ops = &snd_pcm_dshare_fast_ops;
        pcm->private_data = dshare;
        dshare->state = SND_PCM_STATE_OPEN;
-       dshare->slowptr = slowptr;
+       dshare->slowptr = opts->slowptr;
+       dshare->variable_buffer_size = opts->variable_buffer_size;
        dshare->sync_ptr = snd_pcm_dshare_sync_ptr;
 
        if (first_instance) {
@@ -881,8 +876,7 @@ int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
        }
        dopen.ipc_key += ipc_offset;
 
-       err = snd_pcm_dshare_open(pcmp, name, dopen.ipc_key, dopen.ipc_perm, dopen.ipc_gid,
-                                 &params, dopen.bindings, dopen.slowptr,
+       err = snd_pcm_dshare_open(pcmp, name, &dopen, &params,
                                  root, sconf, stream, mode);
        if (err < 0)
                snd_config_delete(sconf);
index a9ea142..8ef8349 100644 (file)
@@ -468,12 +468,8 @@ static snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = {
  * \brief Creates a new dsnoop PCM
  * \param pcmp Returns created PCM handle
  * \param name Name of PCM
- * \param ipc_key IPC key for semaphore and shared memory
- * \param ipc_perm IPC permissions for semaphore and shared memory
- * \param ipc_gid IPC group ID for semaphore and shared memory
+ * \param opts Direct PCM configurations
  * \param params Parameters for slave
- * \param bindings Channel bindings
- * \param slowptr Slow but more precise pointer updates
  * \param root Configuration root
  * \param sconf Slave configuration
  * \param stream PCM Direction (stream)
@@ -484,10 +480,8 @@ static snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = {
  *          changed in future.
  */
 int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
-                       key_t ipc_key, mode_t ipc_perm, int ipc_gid,
+                       struct snd_pcm_direct_open_conf *opts,
                        struct slave_params *params,
-                       snd_config_t *bindings,
-                       int slowptr,
                        snd_config_t *root, snd_config_t *sconf,
                        snd_pcm_stream_t stream, int mode)
 {
@@ -508,13 +502,13 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
                goto _err_nosem;
        }
        
-       ret = snd_pcm_direct_parse_bindings(dsnoop, bindings);
+       ret = snd_pcm_direct_parse_bindings(dsnoop, opts->bindings);
        if (ret < 0)
                goto _err_nosem;
        
-       dsnoop->ipc_key = ipc_key;
-       dsnoop->ipc_perm = ipc_perm;
-       dsnoop->ipc_gid = ipc_gid;
+       dsnoop->ipc_key = opts->ipc_key;
+       dsnoop->ipc_perm = opts->ipc_perm;
+       dsnoop->ipc_gid = opts->ipc_gid;
        dsnoop->semid = -1;
        dsnoop->shmid = -1;
 
@@ -549,7 +543,8 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
        pcm->fast_ops = &snd_pcm_dsnoop_fast_ops;
        pcm->private_data = dsnoop;
        dsnoop->state = SND_PCM_STATE_OPEN;
-       dsnoop->slowptr = slowptr;
+       dsnoop->slowptr = opts->slowptr;
+       dsnoop->variable_buffer_size = opts->variable_buffer_size;
        dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr;
 
        if (first_instance) {
@@ -753,8 +748,7 @@ int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
        }
        dopen.ipc_key += ipc_offset;
 
-       err = snd_pcm_dsnoop_open(pcmp, name, dopen.ipc_key, dopen.ipc_perm, dopen.ipc_gid,
-                                 &params, dopen.bindings, dopen.slowptr,
+       err = snd_pcm_dsnoop_open(pcmp, name, &dopen, &params,
                                  root, sconf, stream, mode);
        if (err < 0)
                snd_config_delete(sconf);