]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Fix mmap with multi plugin
authorTakashi Iwai <tiwai@suse.de>
Fri, 23 Nov 2007 14:46:48 +0000 (15:46 +0100)
committerTakashi Iwai <tiwai@suse.de>
Fri, 23 Nov 2007 14:46:48 +0000 (15:46 +0100)
The mmap of multi plugin seems broken (for a long time!) due to its
creation of local buffer via snd_pcm_mmap().  Since the multi plugin
just needs to shadow the mmap buffer of each slave, it now has
mmap_shadow=1 and its own mmap/unmap method to do shadowing.

src/pcm/pcm_multi.c

index e15038cc194f46376200733cfb39f1e914c9f28d..dfd679cc9f3e0393e3517f1d8ceb330012ddd421 100644 (file)
@@ -690,13 +690,44 @@ static snd_pcm_sframes_t snd_pcm_multi_mmap_commit(snd_pcm_t *pcm,
        return size;
 }
 
-static int snd_pcm_multi_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+static int snd_pcm_multi_munmap(snd_pcm_t *pcm)
 {
+       free(pcm->mmap_channels);
+       free(pcm->running_areas);
+       pcm->mmap_channels = NULL;
+       pcm->running_areas = NULL;
        return 0;
 }
 
-static int snd_pcm_multi_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+static int snd_pcm_multi_mmap(snd_pcm_t *pcm)
 {
+       snd_pcm_multi_t *multi = pcm->private_data;
+       unsigned int c;
+
+       pcm->mmap_channels = calloc(pcm->channels,
+                                   sizeof(pcm->mmap_channels[0]));
+       pcm->running_areas = calloc(pcm->channels,
+                                   sizeof(pcm->running_areas[0]));
+       if (!pcm->mmap_channels || !pcm->running_areas) {
+               snd_pcm_multi_munmap(pcm);
+               return -ENOMEM;
+       }
+
+       /* Copy the slave mmapped buffer data */
+       for (c = 0; c < pcm->channels; c++) {
+               snd_pcm_multi_channel_t *chan = &multi->channels[c];
+               snd_pcm_t *slave;
+               if (chan->slave_idx < 0) {
+                       snd_pcm_multi_munmap(pcm);
+                       return -ENXIO;
+               }
+               slave = multi->slaves[chan->slave_idx].pcm;
+               pcm->mmap_channels[c] =
+                       slave->mmap_channels[chan->slave_channel];
+               pcm->mmap_channels[c].channel = c;
+               pcm->running_areas[c] =
+                       slave->running_areas[chan->slave_channel];
+       }
        return 0;
 }
 
@@ -850,6 +881,7 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name,
                return err;
        }
        pcm->mmap_rw = 1;
+       pcm->mmap_shadow = 1; /* has own mmap method */
        pcm->ops = &snd_pcm_multi_ops;
        pcm->fast_ops = &snd_pcm_multi_fast_ops;
        pcm->private_data = multi;