]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Use O_APPEND mode with dmix & co plugins
authorTakashi Iwai <tiwai@suse.de>
Fri, 28 Apr 2006 13:55:32 +0000 (15:55 +0200)
committerTakashi Iwai <tiwai@suse.de>
Fri, 28 Apr 2006 13:55:32 +0000 (15:55 +0200)
Use O_APPEND mode (only if available) with dmix, dsnoop and dshare
plugins.  Using this mode, the plugin requires no resource server
any more.

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
src/pcm/pcm_hw.c
src/pcm/pcm_local.h

index 46664a13d0a3368527b103ff13a08f3bcfe1ddbb..4e2f36cd275bfda1bc3453e569cf7fb44c317ef3 100644 (file)
@@ -82,6 +82,8 @@ int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix)
        return 0;
 }
 
+#define SND_PCM_DIRECT_MAGIC   0xa15ad319
+
 /*
  *  global shared memory area 
  */
@@ -121,7 +123,13 @@ retryget:
                        buf.shm_perm.gid = dmix->ipc_gid;
                        shmctl(dmix->shmid, IPC_SET, &buf);
                }
+               dmix->shmptr->magic = SND_PCM_DIRECT_MAGIC;
                return 1;
+       } else {
+               if (dmix->shmptr->magic != SND_PCM_DIRECT_MAGIC) {
+                       snd_pcm_direct_shm_discard(dmix);
+                       return -errno;
+               }
        }
        return 0;
 }
@@ -1028,6 +1036,14 @@ int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, str
        dmix->slave_boundary = spcm->boundary;
 
        spcm->donot_close = 1;
+
+       {
+               int ver = 0;
+               ioctl(spcm->poll_fd, SNDRV_PCM_IOCTL_PVERSION, &ver);
+               if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 8))
+                       dmix->shmptr->use_server = 1;
+       }
+
        return 0;
 }
 
@@ -1148,6 +1164,36 @@ int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dm
        return 0;
 }
 
+/*
+ * open a slave PCM as secondary client (dup'ed fd)
+ */
+int snd_pcm_direct_initialize_secondary_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params)
+{
+       int ret;
+
+       spcm->donot_close = 1;
+       spcm->setup = 1;
+       /* we copy the slave setting */
+       spcm->buffer_size = dmix->shmptr->s.buffer_size;
+       spcm->sample_bits = dmix->shmptr->s.sample_bits;
+       spcm->channels = dmix->shmptr->s.channels;
+       spcm->format = dmix->shmptr->s.format;
+       spcm->boundary = recalc_boundary_size(dmix->shmptr->s.boundary, spcm->buffer_size);
+       spcm->info = dmix->shmptr->s.info;
+
+       /* Use the slave setting as SPCM, so far */
+       dmix->slave_buffer_size = spcm->buffer_size;
+       dmix->slave_period_size = dmix->shmptr->s.period_size;
+       dmix->slave_boundary = spcm->boundary;
+
+       ret = snd_pcm_mmap(spcm);
+       if (ret < 0) {
+               SNDERR("unable to mmap channels");
+               return ret;
+       }
+       return 0;
+}
+
 int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix)
 {
        snd_timer_params_t *params;
index b094fcf3d39352bfc5e35ed4a49190378fa24b5a..7cf4b9d5624ef36d7dc2f47600aeff9d6d43a832 100644 (file)
@@ -51,8 +51,10 @@ struct slave_params {
 };
 
 typedef struct {
+       unsigned int magic;                     /* magic number */
        char socket_name[256];                  /* name of communication socket */
        snd_pcm_type_t type;                    /* PCM type (currently only hw) */
+       int use_server;
        struct {
                unsigned int format;
                snd_interval_t rate;
@@ -168,6 +170,7 @@ int snd_pcm_direct_server_discard(snd_pcm_direct_t *dmix);
 int snd_pcm_direct_client_connect(snd_pcm_direct_t *dmix);
 int snd_pcm_direct_client_discard(snd_pcm_direct_t *dmix);
 int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params);
+int snd_pcm_direct_initialize_secondary_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params);
 int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix);
 int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm);
 int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix,
index 366d69f6e58050a3e81a482492d0cbe28cab6338..9bd0bd09af35b9beba76d617f95a60a0b5c3a042 100644 (file)
@@ -650,8 +650,10 @@ static int snd_pcm_dmix_close(snd_pcm_t *pcm)
        if (dmix->client)
                snd_pcm_direct_client_discard(dmix);
        shm_sum_discard(dmix);
-       snd_pcm_direct_shm_discard(dmix);
-       snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
+       if (snd_pcm_direct_shm_discard(dmix))
+               snd_pcm_direct_semaphore_discard(dmix);
+       else
+               snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
        free(dmix->bindings);
        pcm->private_data = NULL;
        free(dmix);
@@ -877,28 +879,54 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
 
                dmix->spcm = spcm;
 
-               dmix->server_free = dmix_server_free;
+               if (dmix->shmptr->use_server) {
+                       dmix->server_free = dmix_server_free;
                
-               ret = snd_pcm_direct_server_create(dmix);
-               if (ret < 0) {
-                       SNDERR("unable to create server");
-                       goto _err;
+                       ret = snd_pcm_direct_server_create(dmix);
+                       if (ret < 0) {
+                               SNDERR("unable to create server");
+                               goto _err;
+                       }
                }
 
                dmix->shmptr->type = spcm->type;
        } else {
-               /* up semaphore to avoid deadlock */
-               snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
-               ret = snd_pcm_direct_client_connect(dmix);
-               if (ret < 0) {
-                       SNDERR("unable to connect client");
-                       goto _err_nosem;
-               }
+               if (dmix->shmptr->use_server) {
+                       /* up semaphore to avoid deadlock */
+                       snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
+                       ret = snd_pcm_direct_client_connect(dmix);
+                       if (ret < 0) {
+                               SNDERR("unable to connect client");
+                               goto _err_nosem;
+                       }
                        
-               snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
-               ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client");
-               if (ret < 0)
-                       goto _err;
+                       snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
+                       ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client");
+                       if (ret < 0)
+                               goto _err;
+               } else {
+
+                       ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
+                                                mode | SND_PCM_NONBLOCK |
+                                                SND_PCM_APPEND,
+                                                NULL);
+                       if (ret < 0) {
+                               SNDERR("unable to open slave");
+                               goto _err;
+                       }
+                       if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
+                               SNDERR("dmix plugin can be only connected to hw plugin");
+                               ret = -EINVAL;
+                               goto _err;
+                       }
+               
+                       ret = snd_pcm_direct_initialize_secondary_slave(dmix, spcm, params);
+                       if (ret < 0) {
+                               SNDERR("unable to initialize slave");
+                               goto _err;
+                       }
+               }
+
                dmix->spcm = spcm;
        }
 
index 88535e567884a6b4435578913f5229c80a3551d7..54f82a33920cad297a7b4f21f339501b1b7999b0 100644 (file)
@@ -464,8 +464,10 @@ static int snd_pcm_dshare_close(snd_pcm_t *pcm)
                snd_pcm_direct_server_discard(dshare);
        if (dshare->client)
                snd_pcm_direct_client_discard(dshare);
-       snd_pcm_direct_shm_discard(dshare);
-       snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
+       if (snd_pcm_direct_shm_discard(dshare))
+               snd_pcm_direct_semaphore_discard(dshare);
+       else
+               snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
        free(dshare->bindings);
        pcm->private_data = NULL;
        free(dshare);
@@ -688,26 +690,53 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
 
                dshare->spcm = spcm;
                
-               ret = snd_pcm_direct_server_create(dshare);
-               if (ret < 0) {
-                       SNDERR("unable to create server");
-                       goto _err;
+               if (dshare->shmptr->use_server) {
+                       ret = snd_pcm_direct_server_create(dshare);
+                       if (ret < 0) {
+                               SNDERR("unable to create server");
+                               goto _err;
+                       }
                }
 
                dshare->shmptr->type = spcm->type;
        } else {
-               /* up semaphore to avoid deadlock */
-               snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
-               ret = snd_pcm_direct_client_connect(dshare);
-               if (ret < 0) {
-                       SNDERR("unable to connect client");
-                       goto _err_nosem;
-               }
+               if (dshare->shmptr->use_server) {
+                       /* up semaphore to avoid deadlock */
+                       snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
+                       ret = snd_pcm_direct_client_connect(dshare);
+                       if (ret < 0) {
+                               SNDERR("unable to connect client");
+                               goto _err_nosem;
+                       }
                        
-               snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT);
-               ret = snd_pcm_direct_open_secondary_client(&spcm, dshare, "dshare_client");
-               if (ret < 0)
-                       goto _err;
+                       snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT);
+                       ret = snd_pcm_direct_open_secondary_client(&spcm, dshare, "dshare_client");
+                       if (ret < 0)
+                               goto _err;
+
+               } else {
+
+                       ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
+                                                mode | SND_PCM_NONBLOCK |
+                                                SND_PCM_APPEND,
+                                                NULL);
+                       if (ret < 0) {
+                               SNDERR("unable to open slave");
+                               goto _err;
+                       }
+                       if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
+                               SNDERR("dshare plugin can be only connected to hw plugin");
+                               ret = -EINVAL;
+                               goto _err;
+                       }
+               
+                       ret = snd_pcm_direct_initialize_secondary_slave(dshare, spcm, params);
+                       if (ret < 0) {
+                               SNDERR("unable to initialize slave");
+                               goto _err;
+                       }
+               }
+
                dshare->spcm = spcm;
        }
 
index 537e09cb786fd2d51269c53f5a5949558eaee7bb..954826f1b25e1a9d34ece3e6169feb0e23a2a3d2 100644 (file)
@@ -360,8 +360,10 @@ static int snd_pcm_dsnoop_close(snd_pcm_t *pcm)
                snd_pcm_direct_server_discard(dsnoop);
        if (dsnoop->client)
                snd_pcm_direct_client_discard(dsnoop);
-       snd_pcm_direct_shm_discard(dsnoop);
-       snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
+       if (snd_pcm_direct_shm_discard(dsnoop))
+               snd_pcm_direct_semaphore_discard(dsnoop);
+       else
+               snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
        free(dsnoop->bindings);
        pcm->private_data = NULL;
        free(dsnoop);
@@ -570,27 +572,53 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
 
                dsnoop->spcm = spcm;
                
-               ret = snd_pcm_direct_server_create(dsnoop);
-               if (ret < 0) {
-                       SNDERR("unable to create server");
-                       goto _err;
+               if (dsnoop->shmptr->use_server) {
+                       ret = snd_pcm_direct_server_create(dsnoop);
+                       if (ret < 0) {
+                               SNDERR("unable to create server");
+                               goto _err;
+                       }
                }
 
                dsnoop->shmptr->type = spcm->type;
        } else {
-               /* up semaphore to avoid deadlock */
-               snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
-               ret = snd_pcm_direct_client_connect(dsnoop);
-               if (ret < 0) {
-                       SNDERR("unable to connect client");
-                       goto _err_nosem;
-               }
+               if (dsnoop->shmptr->use_server) {
+                       /* up semaphore to avoid deadlock */
+                       snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
+                       ret = snd_pcm_direct_client_connect(dsnoop);
+                       if (ret < 0) {
+                               SNDERR("unable to connect client");
+                               goto _err_nosem;
+                       }
                        
-               snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
+                       snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
+
+                       ret = snd_pcm_direct_open_secondary_client(&spcm, dsnoop, "dsnoop_client");
+                       if (ret < 0)
+                               goto _err;
+               } else {
+
+                       ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
+                                                mode | SND_PCM_NONBLOCK |
+                                                SND_PCM_APPEND,
+                                                NULL);
+                       if (ret < 0) {
+                               SNDERR("unable to open slave");
+                               goto _err;
+                       }
+                       if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
+                               SNDERR("dsnoop plugin can be only connected to hw plugin");
+                               ret = -EINVAL;
+                               goto _err;
+                       }
+               
+                       ret = snd_pcm_direct_initialize_secondary_slave(dsnoop, spcm, params);
+                       if (ret < 0) {
+                               SNDERR("unable to initialize slave");
+                               goto _err;
+                       }
+               }
 
-               ret = snd_pcm_direct_open_secondary_client(&spcm, dsnoop, "dsnoop_client");
-               if (ret < 0)
-                       goto _err;
                dsnoop->spcm = spcm;
        }
 
index 59e68dfddac5b6ead304b95b607cd4db72b8931c..5dffb494f1b56686c4f3ff642e4c00a2868cca70 100644 (file)
@@ -1240,6 +1240,8 @@ int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
                fmode |= O_NONBLOCK;
        if (mode & SND_PCM_ASYNC)
                fmode |= O_ASYNC;
+       if (mode & SND_PCM_APPEND)
+               fmode |= O_APPEND;
        fd = snd_open_device(filename, fmode);
        if (fd < 0) {
                ret = -errno;
index be17e7a26738742c70c71d1949eb2e4b1b048b56..e691e6938534b2e3de72512424276d86ec5f10db 100644 (file)
@@ -746,6 +746,8 @@ int snd_pcm_hw_strategy_simple_choices(snd_pcm_hw_strategy_t *strategy, int orde
 int snd_pcm_slave_conf(snd_config_t *root, snd_config_t *conf,
                       snd_config_t **pcm_conf, unsigned int count, ...);
 
+#define SND_PCM_APPEND (1<<8)
+
 int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root,
                       snd_config_t *conf, snd_pcm_stream_t stream,
                       int mode, snd_config_t *parent_conf);