]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Added support for different mmap areas when running or stopped. Cleanings
authorAbramo Bagnara <abramo@alsa-project.org>
Sat, 7 Oct 2000 16:59:48 +0000 (16:59 +0000)
committerAbramo Bagnara <abramo@alsa-project.org>
Sat, 7 Oct 2000 16:59:48 +0000 (16:59 +0000)
16 files changed:
include/pcm.h
src/pcm/pcm.c
src/pcm/pcm_adpcm.c
src/pcm/pcm_alaw.c
src/pcm/pcm_client.c
src/pcm/pcm_file.c
src/pcm/pcm_hw.c
src/pcm/pcm_linear.c
src/pcm/pcm_local.h
src/pcm/pcm_mmap.c
src/pcm/pcm_mulaw.c
src/pcm/pcm_multi.c
src/pcm/pcm_plug.c
src/pcm/pcm_plugin.c
src/pcm/pcm_rate.c
src/pcm/pcm_route.c

index 54d3826528ca846fa1d70670b947f7664d5c7528..55c2c7ce653d0eb2187bc14ed88287efbe3fd3ca 100644 (file)
@@ -110,8 +110,9 @@ typedef enum {
        SND_PCM_TYPE_ADPCM,
        SND_PCM_TYPE_RATE,
        SND_PCM_TYPE_ROUTE,
-       SND_PCM_TYPE_COPY,
        SND_PCM_TYPE_PLUG,
+       SND_PCM_TYPE_SHARE,
+       SND_PCM_TYPE_MIX,
        SND_PCM_TYPE_DROUTE,
        SND_PCM_TYPE_LBSERVER,
 } snd_pcm_type_t;
@@ -127,56 +128,57 @@ int snd_pcm_plug_open_subdevice(snd_pcm_t **handle, int card, int device, int su
 int snd_pcm_plug_open_device(snd_pcm_t **handle, int card, int device, int stream, int mode);
 #define snd_pcm_write snd_pcm_writei
 #define snd_pcm_read snd_pcm_readi
-ssize_t snd_pcm_writev(snd_pcm_t *handle, const struct iovec *vector, int count);
-ssize_t snd_pcm_readv(snd_pcm_t *handle, const struct iovec *vector, int count);
-
-
-snd_pcm_type_t snd_pcm_type(snd_pcm_t *handle);
-int snd_pcm_close(snd_pcm_t *handle);
-int snd_pcm_poll_descriptor(snd_pcm_t *handle);
-int snd_pcm_nonblock(snd_pcm_t *handle, int nonblock);
-int snd_pcm_info(snd_pcm_t *handle, snd_pcm_info_t *info);
-int snd_pcm_params_info(snd_pcm_t *handle, snd_pcm_params_info_t *info);
-int snd_pcm_params(snd_pcm_t *handle, snd_pcm_params_t *params);
-int snd_pcm_setup(snd_pcm_t *handle, snd_pcm_setup_t *setup);
-int snd_pcm_channel_info(snd_pcm_t *handle, snd_pcm_channel_info_t *info);
-int snd_pcm_channel_params(snd_pcm_t *handle, snd_pcm_channel_params_t *params);
-int snd_pcm_channel_setup(snd_pcm_t *handle, snd_pcm_channel_setup_t *setup);
-int snd_pcm_status(snd_pcm_t *handle, snd_pcm_status_t *status);
-int snd_pcm_prepare(snd_pcm_t *handle);
-int snd_pcm_start(snd_pcm_t *handle);
-int snd_pcm_drop(snd_pcm_t *handle);
-int snd_pcm_drain(snd_pcm_t *handle);
-int snd_pcm_pause(snd_pcm_t *handle, int enable);
-int snd_pcm_state(snd_pcm_t *handle);
-int snd_pcm_delay(snd_pcm_t *handle, ssize_t *delayp);
-ssize_t snd_pcm_rewind(snd_pcm_t *handle, size_t frames);
-ssize_t snd_pcm_writei(snd_pcm_t *handle, const void *buffer, size_t size);
-ssize_t snd_pcm_readi(snd_pcm_t *handle, void *buffer, size_t size);
-ssize_t snd_pcm_writen(snd_pcm_t *handle, void **bufs, size_t size);
-ssize_t snd_pcm_readn(snd_pcm_t *handle, void **bufs, size_t size);
-int snd_pcm_dump_setup(snd_pcm_t *handle, FILE *fp);
-int snd_pcm_dump(snd_pcm_t *handle, FILE *fp);
+ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, int count);
+ssize_t snd_pcm_readv(snd_pcm_t *pcm, const struct iovec *vector, int count);
+
+
+snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm);
+int snd_pcm_close(snd_pcm_t *pcm);
+int snd_pcm_poll_descriptor(snd_pcm_t *pcm);
+int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock);
+int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info);
+int snd_pcm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info);
+int snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params);
+int snd_pcm_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup);
+int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info);
+int snd_pcm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params);
+int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup);
+int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status);
+int snd_pcm_prepare(snd_pcm_t *pcm);
+int snd_pcm_start(snd_pcm_t *pcm);
+int snd_pcm_drop(snd_pcm_t *pcm);
+int snd_pcm_drain(snd_pcm_t *pcm);
+int snd_pcm_pause(snd_pcm_t *pcm, int enable);
+int snd_pcm_state(snd_pcm_t *pcm);
+int snd_pcm_delay(snd_pcm_t *pcm, ssize_t *delayp);
+ssize_t snd_pcm_rewind(snd_pcm_t *pcm, size_t frames);
+ssize_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, size_t size);
+ssize_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, size_t size);
+ssize_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, size_t size);
+ssize_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, size_t size);
+int snd_pcm_dump_setup(snd_pcm_t *pcm, FILE *fp);
+int snd_pcm_dump(snd_pcm_t *pcm, FILE *fp);
 int snd_pcm_dump_status(snd_pcm_status_t *status, FILE *fp);
-int snd_pcm_link(snd_pcm_t *handle1, snd_pcm_t *handle2);
-int snd_pcm_unlink(snd_pcm_t *handle);
+int snd_pcm_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2);
+int snd_pcm_unlink(snd_pcm_t *pcm);
 
-int snd_pcm_channels_mask(snd_pcm_t *handle, bitset_t *cmask);
+int snd_pcm_channels_mask(snd_pcm_t *pcm, bitset_t *cmask);
 int snd_pcm_wait(snd_pcm_t *pcm, int timeout);
 ssize_t snd_pcm_avail_update(snd_pcm_t *pcm);
 
 
 /* mmap */
-int snd_pcm_mmap(snd_pcm_t *handle, void **buffer);
-int snd_pcm_munmap(snd_pcm_t *handle);
-int snd_pcm_mmap_get_areas(snd_pcm_t *handle, snd_pcm_channel_area_t *areas);
+int snd_pcm_mmap(snd_pcm_t *pcm, void **buffer);
+int snd_pcm_munmap(snd_pcm_t *pcm);
+snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm);
+int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas);
 ssize_t snd_pcm_mmap_forward(snd_pcm_t *pcm, size_t size);
 size_t snd_pcm_mmap_offset(snd_pcm_t *pcm);
 size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t size);
-ssize_t snd_pcm_mmap_writei(snd_pcm_t *handle, const void *buffer, size_t size);
-ssize_t snd_pcm_mmap_readi(snd_pcm_t *handle, void *buffer, size_t size);
-ssize_t snd_pcm_mmap_writen(snd_pcm_t *handle, void **bufs, size_t size);
-ssize_t snd_pcm_mmap_readn(snd_pcm_t *handle, void **bufs, size_t size);
+ssize_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, size_t size);
+ssize_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, size_t size);
+ssize_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, size_t size);
+ssize_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, size_t size);
 
 const char *snd_pcm_format_name(int format);
 const char *snd_pcm_format_description(int format);
index 9c1b5bd4c61649ff9d6f72b637c8a983267187d7..109776762652602a4d6c965bad532c529525533e 100644 (file)
@@ -653,6 +653,7 @@ ssize_t snd_pcm_avail_update(snd_pcm_t *pcm)
 ssize_t snd_pcm_mmap_forward(snd_pcm_t *pcm, size_t size)
 {
        assert(size > 0);
+       assert(size <= snd_pcm_mmap_avail(pcm));
        return pcm->fast_ops->mmap_forward(pcm->fast_op_arg, size);
 }
 
index f02fbae307bd0096e8b0d405db2607aeb221753e..ee6580ceeab51a5c12f8d6f8e840deaec8568a08 100644 (file)
@@ -466,7 +466,7 @@ static ssize_t snd_pcm_adpcm_write_areas(snd_pcm_t *pcm,
        while (xfer < size) {
                size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
                adpcm->func(areas, offset, 
-                           slave->mmap_areas, snd_pcm_mmap_offset(slave),
+                           snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                            frames, pcm->setup.format.channels,
                            adpcm->getput_idx, adpcm->states);
                err = snd_pcm_mmap_forward(slave, frames);
@@ -500,7 +500,7 @@ static ssize_t snd_pcm_adpcm_read_areas(snd_pcm_t *pcm,
        assert(size > 0);
        while (xfer < size) {
                size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
-               adpcm->func(slave->mmap_areas, snd_pcm_mmap_offset(slave),
+               adpcm->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                            areas, offset, 
                            frames, pcm->setup.format.channels,
                            adpcm->getput_idx, adpcm->states);
index 570de5954a88d0af6f0e2f91a6130acaa4cc5208..2646de9e2915ffea2cff727d0d2b005c0a1f38c6 100644 (file)
@@ -334,7 +334,7 @@ static ssize_t snd_pcm_alaw_write_areas(snd_pcm_t *pcm,
        while (xfer < size) {
                size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
                alaw->func(areas, offset, 
-                           slave->mmap_areas, snd_pcm_mmap_offset(slave),
+                           snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                            frames, pcm->setup.format.channels,
                            alaw->getput_idx);
                err = snd_pcm_mmap_forward(slave, frames);
@@ -368,7 +368,7 @@ static ssize_t snd_pcm_alaw_read_areas(snd_pcm_t *pcm,
        assert(size > 0);
        while (xfer < size) {
                size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
-               alaw->func(slave->mmap_areas, snd_pcm_mmap_offset(slave),
+               alaw->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                           areas, offset, 
                           frames, pcm->setup.format.channels,
                           alaw->getput_idx);
index 9a928d5f9896b9782a0352f0bf55693fcc1c3d08..2652ab1a6f69f54ffff95691566c406c6fea6fe7 100644 (file)
@@ -470,7 +470,7 @@ static int snd_pcm_client_shm_munmap_status(snd_pcm_t *pcm)
        if (err < 0)
                return err;
        /* FIXME: not mmap */
-       if (munmap(pcm->mmap_status, sizeof(*pcm->mmap_status)) < 0)
+       if (munmap((void*)pcm->mmap_status, sizeof(*pcm->mmap_status)) < 0)
                return -errno;
        return ctrl->result;
 }
index cf2b1f58411b86c92f6532b01a6e07ccc8db3eff..acb09a57c99fd14fb9e33d32ba75f67929eb1944 100644 (file)
@@ -141,19 +141,23 @@ static void snd_pcm_file_write_areas(snd_pcm_t *pcm,
 {
        snd_pcm_file_t *file = pcm->private;
        size_t bytes = snd_pcm_frames_to_bytes(pcm, frames);
-       char buf[bytes];
+       char *buf;
        size_t channels = pcm->setup.format.channels;
        snd_pcm_channel_area_t buf_areas[channels];
        size_t channel;
        ssize_t r;
-       for (channel = 0; channel < channels; ++channel) {
-               snd_pcm_channel_area_t *a = &buf_areas[channel];
-               a->addr = buf;
-               a->first = pcm->bits_per_sample * channel;
-               a->step = pcm->bits_per_frame;
-       }
-       snd_pcm_areas_copy(areas, offset, buf_areas, 0, 
-                          channels, frames, pcm->setup.format.sfmt);
+       if (pcm->setup.mmap_shape != SND_PCM_MMAP_INTERLEAVED) {
+               buf = alloca(bytes);
+               for (channel = 0; channel < channels; ++channel) {
+                       snd_pcm_channel_area_t *a = &buf_areas[channel];
+                       a->addr = buf;
+                       a->first = pcm->bits_per_sample * channel;
+                       a->step = pcm->bits_per_frame;
+               }
+               snd_pcm_areas_copy(areas, offset, buf_areas, 0, 
+                                  channels, frames, pcm->setup.format.sfmt);
+       } else
+               buf = snd_pcm_channel_area_addr(areas, offset);
        r = write(file->fd, buf, bytes);
        assert(r == (ssize_t)bytes);
 }
@@ -219,7 +223,7 @@ static ssize_t snd_pcm_file_mmap_forward(snd_pcm_t *pcm, size_t size)
                size_t cont = pcm->setup.buffer_size - ofs;
                if (cont < frames)
                        frames = cont;
-               snd_pcm_file_write_areas(pcm, pcm->mmap_areas, ofs, frames);
+               snd_pcm_file_write_areas(pcm, snd_pcm_mmap_areas(file->slave), ofs, frames);
                ofs += frames;
                if (ofs == pcm->setup.buffer_size)
                        ofs = 0;
@@ -237,19 +241,31 @@ static ssize_t snd_pcm_file_avail_update(snd_pcm_t *pcm)
 static int snd_pcm_file_mmap_status(snd_pcm_t *pcm)
 {
        snd_pcm_file_t *file = pcm->private;
-       return snd_pcm_mmap_status(file->slave, &pcm->mmap_status);
+       int err = snd_pcm_mmap_status(file->slave, &pcm->mmap_status);
+       if (err < 0)
+               return err;
+       pcm->mmap_status = file->slave->mmap_status;
+       return 0;
 }
 
 static int snd_pcm_file_mmap_control(snd_pcm_t *pcm)
 {
        snd_pcm_file_t *file = pcm->private;
-       return snd_pcm_mmap_control(file->slave, &pcm->mmap_control);
+       int err = snd_pcm_mmap_control(file->slave, &pcm->mmap_control);
+       if (err < 0)
+               return err;
+       pcm->mmap_control = file->slave->mmap_control;
+       return 0;
 }
 
 static int snd_pcm_file_mmap_data(snd_pcm_t *pcm)
 {
        snd_pcm_file_t *file = pcm->private;
-       return snd_pcm_mmap_data(file->slave, &pcm->mmap_data);
+       int err = snd_pcm_mmap_data(file->slave, &pcm->mmap_data);
+       if (err < 0)
+               return err;
+       pcm->mmap_data = file->slave->mmap_data;
+       return 0;
 }
 
 static int snd_pcm_file_munmap_status(snd_pcm_t *pcm)
index 91f2e5b6f01733bbaf9da7c4bac6d93291114f89..795b05948d8f7ae3d93f53d14c9fbd252a4133cc 100644 (file)
@@ -137,16 +137,19 @@ static int snd_pcm_hw_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * se
                return -errno;
        if (hw->mmap_emulation) {
                if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
-                       setup->area.addr = pcm->mmap_data;
-                       setup->area.first = setup->channel * pcm->bits_per_sample;
-                       setup->area.step = pcm->bits_per_frame;
+                       setup->running_area.addr = pcm->mmap_data;
+                       setup->running_area.first = setup->channel * pcm->bits_per_sample;
+                       setup->running_area.step = pcm->bits_per_frame;
                } else {
-                       setup->area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
-                       setup->area.first = 0;
-                       setup->area.step = pcm->bits_per_sample;
+                       setup->running_area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
+                       setup->running_area.first = 0;
+                       setup->running_area.step = pcm->bits_per_sample;
                }
-       } else
-               setup->area.addr = (char *)pcm->mmap_data + (long)setup->area.addr;
+               setup->stopped_area = setup->running_area;
+       } else {
+               setup->running_area.addr = (char *)pcm->mmap_data + (long)setup->running_area.addr;
+               setup->stopped_area.addr = setup->running_area.addr;
+       }
        return 0;
 }
 
@@ -220,18 +223,18 @@ static int snd_pcm_hw_pause(snd_pcm_t *pcm, int enable)
 
 static ssize_t snd_pcm_hw_rewind(snd_pcm_t *pcm, size_t frames)
 {
-       ssize_t used;
+       ssize_t hw_avail;
        if (pcm->setup.xrun_mode == SND_PCM_XRUN_ASAP) {
                ssize_t d;
                int err = snd_pcm_hw_delay(pcm, &d);
                if (err < 0)
                        return 0;
        }
-       used = pcm->setup.buffer_size - snd_pcm_mmap_avail(pcm);
-       if (used <= 0)
+       hw_avail = snd_pcm_mmap_hw_avail(pcm);
+       if (hw_avail <= 0)
                return 0;
-       if (frames > (size_t)used)
-               frames = used;
+       if (frames > (size_t)hw_avail)
+               frames = hw_avail;
        snd_pcm_mmap_appl_backward(pcm, frames);
        return frames;
 }
@@ -339,7 +342,7 @@ static int snd_pcm_hw_mmap_data(snd_pcm_t *pcm)
 
 static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm)
 {
-       if (munmap(pcm->mmap_status, sizeof(*pcm->mmap_status)) < 0)
+       if (munmap((void*)pcm->mmap_status, sizeof(*pcm->mmap_status)) < 0)
                return -errno;
        return 0;
 }
@@ -377,7 +380,8 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
        int fd = hw->fd;
        size_t avail;
        ssize_t err;
-       if (pcm->setup.ready_mode == SND_PCM_READY_ASAP) {
+       if (pcm->setup.ready_mode == SND_PCM_READY_ASAP ||
+           pcm->setup.xrun_mode == SND_PCM_XRUN_ASAP) {
                ssize_t d;
                int err = ioctl(fd, SND_PCM_IOCTL_DELAY, &d);
                if (err < 0)
@@ -395,6 +399,8 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
                        return err;
                }
        }
+       if (avail >= pcm->setup.buffer_size)
+               return -EPIPE;
        return avail;
 }
 
index 277be5b19b67ef9f24da7d7a5a05820c85e66578..b3cea851f1eec3c9162186b24e6ee15adf753eed 100644 (file)
@@ -179,7 +179,7 @@ static ssize_t snd_pcm_linear_write_areas(snd_pcm_t *pcm,
        while (xfer < size) {
                size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
                linear_transfer(areas, offset, 
-                               slave->mmap_areas, snd_pcm_mmap_offset(slave),
+                               snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                                frames, pcm->setup.format.channels, linear->conv_idx);
                err = snd_pcm_mmap_forward(slave, frames);
                if (err < 0)
@@ -212,7 +212,7 @@ static ssize_t snd_pcm_linear_read_areas(snd_pcm_t *pcm,
        assert(size > 0);
        while (xfer < size) {
                size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
-               linear_transfer(slave->mmap_areas, snd_pcm_mmap_offset(slave),
+               linear_transfer(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                                areas, offset, 
                                frames, pcm->setup.format.channels, linear->conv_idx);
                err = snd_pcm_mmap_forward(slave, frames);
index 0409abc8cb4ed591e1d77a659f49a2d2b68adfc7..c6fb580819154ac474480d18730a36f78d5109fa 100644 (file)
@@ -73,10 +73,11 @@ struct snd_pcm {
        snd_pcm_setup_t setup;
        size_t bits_per_sample;
        size_t bits_per_frame;
-       snd_pcm_mmap_status_t *mmap_status;
+       volatile snd_pcm_mmap_status_t *mmap_status;
        snd_pcm_mmap_control_t *mmap_control;
        void *mmap_data;
-       snd_pcm_channel_area_t *mmap_areas;
+       snd_pcm_channel_area_t *running_areas;
+       snd_pcm_channel_area_t *stopped_areas;
        struct snd_pcm_ops *ops;
        struct snd_pcm_fast_ops *fast_ops;
        snd_pcm_t *op_arg;
@@ -88,7 +89,7 @@ int snd_pcm_init(snd_pcm_t *pcm);
 void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void *buf);
 void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void **bufs);
 
-int snd_pcm_mmap_status(snd_pcm_t *pcm, snd_pcm_mmap_status_t **status);
+int snd_pcm_mmap_status(snd_pcm_t *pcm, volatile snd_pcm_mmap_status_t **status);
 int snd_pcm_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t **control);
 int snd_pcm_mmap_data(snd_pcm_t *pcm, void **buffer);
 int snd_pcm_munmap_status(snd_pcm_t *pcm);
@@ -101,7 +102,6 @@ void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, size_t frames);
 void snd_pcm_mmap_hw_backward(snd_pcm_t *pcm, size_t frames);
 void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, size_t frames);
 size_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm);
-size_t snd_pcm_mmap_avail(snd_pcm_t *pcm);
 size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames);
 size_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, size_t frames);
 
@@ -137,6 +137,54 @@ static inline size_t snd_pcm_mmap_capture_avail(snd_pcm_t *pcm)
        return avail;
 }
 
+static inline size_t snd_pcm_mmap_avail(snd_pcm_t *pcm)
+{
+       if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+               return snd_pcm_mmap_playback_avail(pcm);
+       else
+               return snd_pcm_mmap_capture_avail(pcm);
+       return 0;
+}
+
+static inline ssize_t snd_pcm_mmap_playback_hw_avail(snd_pcm_t *pcm)
+{
+       ssize_t avail;
+       avail = pcm->mmap_status->hw_ptr + pcm->setup.buffer_size - pcm->mmap_control->appl_ptr;
+       if (avail < 0)
+               avail += pcm->setup.boundary;
+       return pcm->setup.buffer_size - avail;
+}
+
+static inline ssize_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
+{
+       ssize_t avail;
+       avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr;
+       if (avail < 0)
+               avail += pcm->setup.boundary;
+       return pcm->setup.buffer_size - avail;
+}
+
+static inline ssize_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm)
+{
+       if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+               return snd_pcm_mmap_playback_hw_avail(pcm);
+       else
+               return snd_pcm_mmap_capture_hw_avail(pcm);
+       return 0;
+}
+
+#define snd_pcm_mmap_playback_delay snd_pcm_mmap_playback_hw_avail
+#define snd_pcm_mmap_capture_delay snd_pcm_mmap_capture_avail
+
+static inline ssize_t snd_pcm_mmap_delay(snd_pcm_t *pcm)
+{
+       if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+               return snd_pcm_mmap_playback_delay(pcm);
+       else
+               return snd_pcm_mmap_capture_delay(pcm);
+       return 0;
+}
+
 static inline void *snd_pcm_channel_area_addr(snd_pcm_channel_area_t *area, size_t offset)
 {
        size_t bitofs = area->first + area->step * offset;
index 3264f6486c547587908aadff551d215020a91882..e3afe0b29572b10960bc81462dfdca7b633c546f 100644 (file)
 #include <sys/poll.h>
 #include "pcm_local.h"
 
-size_t snd_pcm_mmap_avail(snd_pcm_t *pcm)
+snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm)
 {
-        assert(pcm);
-       assert(pcm->mmap_status && pcm->mmap_control);
-       if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
-               return snd_pcm_mmap_playback_avail(pcm);
-       else
-               return snd_pcm_mmap_capture_avail(pcm);
-       return 0;
+  int state = snd_pcm_state(pcm);
+  if (state == SND_PCM_STATE_RUNNING)
+         return pcm->running_areas;
+  else
+         return pcm->stopped_areas;
 }
 
 size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames)
@@ -136,7 +134,7 @@ ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm,
        while (xfer < size) {
                size_t frames = snd_pcm_mmap_playback_xfer(pcm, size - xfer);
                snd_pcm_areas_copy(areas, offset, 
-                                  pcm->mmap_areas, snd_pcm_mmap_offset(pcm),
+                                  snd_pcm_mmap_areas(pcm), snd_pcm_mmap_offset(pcm),
                                   pcm->setup.format.channels, 
                                   frames, pcm->setup.format.sfmt);
                err = snd_pcm_mmap_forward(pcm, frames);
@@ -167,7 +165,7 @@ ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm,
        xfer = 0;
        while (xfer < size) {
                size_t frames = snd_pcm_mmap_capture_xfer(pcm, size - xfer);
-               snd_pcm_areas_copy(pcm->mmap_areas, snd_pcm_mmap_offset(pcm),
+               snd_pcm_areas_copy(snd_pcm_mmap_areas(pcm), snd_pcm_mmap_offset(pcm),
                                   areas, offset, 
                                   pcm->setup.format.channels, 
                                   frames, pcm->setup.format.sfmt);
@@ -218,18 +216,14 @@ ssize_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, size_t size)
                                  snd_pcm_mmap_read_areas);
 }
 
-int snd_pcm_mmap_status(snd_pcm_t *pcm, snd_pcm_mmap_status_t **status)
+int snd_pcm_mmap_status(snd_pcm_t *pcm, volatile snd_pcm_mmap_status_t **status)
 {
        int err;
        assert(pcm);
-       if (pcm->mmap_status) {
-               if (status)
-                       *status = pcm->mmap_status;
-               return 0;
+       if (!pcm->mmap_status) {
+               if ((err = pcm->ops->mmap_status(pcm->op_arg)) < 0)
+                       return err;
        }
-
-       if ((err = pcm->ops->mmap_status(pcm->op_arg)) < 0)
-               return err;
        if (status)
                *status = pcm->mmap_status;
        return 0;
@@ -239,40 +233,44 @@ int snd_pcm_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t **control)
 {
        int err;
        assert(pcm);
-       if (pcm->mmap_control) {
-               if (control)
-                       *control = pcm->mmap_control;
-               return 0;
+       if (!pcm->mmap_control) {
+               if ((err = pcm->ops->mmap_control(pcm->op_arg)) < 0)
+                       return err;
        }
-
-       if ((err = pcm->ops->mmap_control(pcm->op_arg)) < 0)
-               return err;
        if (control)
                *control = pcm->mmap_control;
        return 0;
 }
 
-int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas)
+int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas)
 {
-       snd_pcm_channel_setup_t s;
-       snd_pcm_channel_area_t *a, *ap;
+       snd_pcm_channel_setup_t setup;
+       snd_pcm_channel_area_t *r, *rp, *s, *sp;
        unsigned int channel;
        int err;
        assert(pcm);
        assert(pcm->mmap_data);
-       a = calloc(pcm->setup.format.channels, sizeof(*areas));
-       for (channel = 0, ap = a; channel < pcm->setup.format.channels; ++channel, ++ap) {
-               s.channel = channel;
-               err = snd_pcm_channel_setup(pcm, &s);
-               if (err < 0) {
-                       free(a);
-                       return err;
+       if (!pcm->running_areas) {
+               r = calloc(pcm->setup.format.channels, sizeof(*r));
+               s = calloc(pcm->setup.format.channels, sizeof(*s));
+               for (channel = 0, rp = r, sp = s; channel < pcm->setup.format.channels; ++channel, ++rp, ++sp) {
+                       setup.channel = channel;
+                       err = snd_pcm_channel_setup(pcm, &setup);
+                       if (err < 0) {
+                               free(r);
+                               free(s);
+                               return err;
+                       }
+                       *rp = setup.running_area;
+                       *sp = setup.stopped_area;
                }
-               if (areas)
-                       areas[channel] = s.area;
-               *ap = s.area;
+               pcm->running_areas = r;
+               pcm->stopped_areas = s;
        }
-       pcm->mmap_areas = a;
+       if (running_areas)
+               memcpy(running_areas, pcm->running_areas, pcm->setup.format.channels * sizeof(*running_areas));
+       if (stopped_areas)
+               memcpy(stopped_areas, pcm->stopped_areas, pcm->setup.format.channels * sizeof(*stopped_areas));
        return 0;
 }
 
@@ -291,7 +289,7 @@ int snd_pcm_mmap_data(snd_pcm_t *pcm, void **data)
                return err;
        if (data) 
                *data = pcm->mmap_data;
-       err = snd_pcm_mmap_get_areas(pcm, NULL);
+       err = snd_pcm_mmap_get_areas(pcm, NULL, NULL);
        if (err < 0)
                return err;
        return 0;
@@ -326,8 +324,10 @@ int snd_pcm_munmap_data(snd_pcm_t *pcm)
        assert(pcm->mmap_data);
        if ((err = pcm->ops->munmap_data(pcm->op_arg)) < 0)
                return err;
-       free(pcm->mmap_areas);
-       pcm->mmap_areas = 0;
+       free(pcm->stopped_areas);
+       free(pcm->running_areas);
+       pcm->stopped_areas = 0;
+       pcm->running_areas = 0;
        pcm->mmap_data = 0;
        return 0;
 }
@@ -355,7 +355,7 @@ ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size)
                if (cont < frames)
                        frames = cont;
                if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
-                       snd_pcm_channel_area_t *a = pcm->mmap_areas;
+                       snd_pcm_channel_area_t *a = snd_pcm_mmap_areas(pcm);
                        char *buf = snd_pcm_channel_area_addr(a, offset);
                        assert(pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED);
                        err = _snd_pcm_writei(pcm, buf, size);
@@ -363,9 +363,10 @@ ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size)
                        size_t channels = pcm->setup.format.channels;
                        unsigned int c;
                        void *bufs[channels];
+                       snd_pcm_channel_area_t *areas = snd_pcm_mmap_areas(pcm);
                        assert(pcm->setup.mmap_shape == SND_PCM_MMAP_NONINTERLEAVED);
                        for (c = 0; c < channels; ++c) {
-                               snd_pcm_channel_area_t *a = &pcm->mmap_areas[c];
+                               snd_pcm_channel_area_t *a = &areas[c];
                                bufs[c] = snd_pcm_channel_area_addr(a, offset);
                        }
                        err = _snd_pcm_writen(pcm, bufs, size);
@@ -391,7 +392,7 @@ ssize_t snd_pcm_read_mmap(snd_pcm_t *pcm, size_t size)
                if (cont < frames)
                        frames = cont;
                if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
-                       snd_pcm_channel_area_t *a = pcm->mmap_areas;
+                       snd_pcm_channel_area_t *a = snd_pcm_mmap_areas(pcm);
                        char *buf = snd_pcm_channel_area_addr(a, offset);
                        assert(pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED);
                        err = _snd_pcm_readi(pcm, buf, size);
@@ -399,9 +400,10 @@ ssize_t snd_pcm_read_mmap(snd_pcm_t *pcm, size_t size)
                        size_t channels = pcm->setup.format.channels;
                        unsigned int c;
                        void *bufs[channels];
+                       snd_pcm_channel_area_t *areas = snd_pcm_mmap_areas(pcm);
                        assert(pcm->setup.mmap_shape == SND_PCM_MMAP_NONINTERLEAVED);
                        for (c = 0; c < channels; ++c) {
-                               snd_pcm_channel_area_t *a = &pcm->mmap_areas[c];
+                               snd_pcm_channel_area_t *a = &areas[c];
                                bufs[c] = snd_pcm_channel_area_addr(a, offset);
                        }
                        err = _snd_pcm_readn(pcm->fast_op_arg, bufs, size);
index 14fc3c3a18c22155bd0c874cfa1436b6090fd0be..1139717d1012b1a2e6bd31e4e4ff5fbde43c0d4c 100644 (file)
@@ -351,7 +351,7 @@ static ssize_t snd_pcm_mulaw_write_areas(snd_pcm_t *pcm,
        while (xfer < size) {
                size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
                mulaw->func(areas, offset, 
-                           slave->mmap_areas, snd_pcm_mmap_offset(slave),
+                           snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                            frames, pcm->setup.format.channels,
                            mulaw->getput_idx);
                err = snd_pcm_mmap_forward(slave, frames);
@@ -385,7 +385,7 @@ static ssize_t snd_pcm_mulaw_read_areas(snd_pcm_t *pcm,
        assert(size > 0);
        while (xfer < size) {
                size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
-               mulaw->func(slave->mmap_areas, snd_pcm_mmap_offset(slave),
+               mulaw->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                            areas, offset, 
                            frames, pcm->setup.format.channels,
                            mulaw->getput_idx);
index f9c0990df956b28c6b22ff5b62da4784cce68351..b97e1d1b4605bd7e5585276f4fa374fede5b9416 100644 (file)
@@ -165,9 +165,6 @@ static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
                                return err;
                }
                p.format.channels = multi->slaves[i].channels_count;
-#if 1
-               p.xrun_mode = SND_PCM_XRUN_NONE;
-#endif
                err = snd_pcm_params(slave, &p);
                if (err < 0) {
                        params->fail_mask = p.fail_mask;
@@ -180,7 +177,7 @@ static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
                snd_pcm_mmap_data(slave, NULL);
                if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
                    err == 0)
-                       snd_pcm_areas_silence(slave->mmap_areas, 0, slave->setup.format.channels, 
+                       snd_pcm_areas_silence(snd_pcm_mmap_areas(slave), 0, slave->setup.format.channels, 
                                              slave->setup.buffer_size, slave->setup.format.sfmt);
        }
        if (err == 0)
@@ -368,11 +365,15 @@ static int snd_pcm_multi_mmap_data(snd_pcm_t *pcm)
                        return err;
                setup = &slave->setup;
                if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
-                       snd_pcm_channel_area_t areas[setup->format.channels];
-                       err = snd_pcm_mmap_get_areas(slave, areas);
+                       snd_pcm_channel_area_t r[setup->format.channels];
+                       snd_pcm_channel_area_t s[setup->format.channels];
+                       err = snd_pcm_mmap_get_areas(slave, s, r);
                        if (err < 0)
                                return err;
-                       err = snd_pcm_areas_silence(areas, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
+                       err = snd_pcm_areas_silence(s, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
+                       if (err < 0)
+                               return err;
+                       err = snd_pcm_areas_silence(r, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
                        if (err < 0)
                                return err;
                }
index 61c418d149fcce54621ba120d6a057dcfc8fdb1b..b46ef67327b54d4fbaf5ec052d9fe85ab48745db 100644 (file)
@@ -595,19 +595,31 @@ static int snd_pcm_plug_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *s
 static int snd_pcm_plug_mmap_status(snd_pcm_t *pcm)
 {
        snd_pcm_plug_t *plug = pcm->private;
-       return snd_pcm_mmap_status(plug->slave, NULL);
+       int err = snd_pcm_mmap_status(plug->slave, NULL);
+       if (err < 0)
+               return err;
+       pcm->mmap_status = plug->slave->mmap_status;
+       return 0;
 }
 
 static int snd_pcm_plug_mmap_control(snd_pcm_t *pcm)
 {
        snd_pcm_plug_t *plug = pcm->private;
-       return snd_pcm_mmap_control(plug->slave, NULL);
+       int err = snd_pcm_mmap_control(plug->slave, NULL);
+       if (err < 0)
+               return err;
+       pcm->mmap_control = plug->slave->mmap_control;
+       return 0;
 }
 
 static int snd_pcm_plug_mmap_data(snd_pcm_t *pcm)
 {
        snd_pcm_plug_t *plug = pcm->private;
-       return snd_pcm_mmap_data(plug->slave, NULL);
+       int err = snd_pcm_mmap_data(plug->slave, NULL);
+       if (err < 0)
+               return err;
+       pcm->mmap_data = plug->slave->mmap_data;
+       return 0;
 }
 
 static int snd_pcm_plug_munmap_status(snd_pcm_t *pcm)
index 15894576d03af1255cd8e3dc40c83fae1668eb59..6a8630569b02313f59f48e8e3934bb47b0e772e4 100644 (file)
@@ -65,14 +65,15 @@ int snd_pcm_plugin_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup
        if (err < 0)
                return err;
        if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
-               setup->area.addr = pcm->mmap_data;
-               setup->area.first = setup->channel * pcm->bits_per_sample;
-               setup->area.step = pcm->bits_per_frame;
+               setup->running_area.addr = pcm->mmap_data;
+               setup->running_area.first = setup->channel * pcm->bits_per_sample;
+               setup->running_area.step = pcm->bits_per_frame;
        } else {
-               setup->area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
-               setup->area.first = 0;
-               setup->area.step = pcm->bits_per_sample;
+               setup->running_area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
+               setup->running_area.first = 0;
+               setup->running_area.step = pcm->bits_per_sample;
        }
+       setup->stopped_area = setup->running_area;
        return 0;
 }
 
@@ -95,17 +96,13 @@ int snd_pcm_plugin_state(snd_pcm_t *pcm)
 int snd_pcm_plugin_delay(snd_pcm_t *pcm, ssize_t *delayp)
 {
        snd_pcm_plugin_t *plugin = pcm->private;
-       ssize_t sd, d;
+       ssize_t sd;
        int err = snd_pcm_delay(plugin->slave, &sd);
        if (err < 0)
                return err;
        if (plugin->client_frames)
                sd = plugin->client_frames(pcm, sd);
-       if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
-               d = pcm->setup.buffer_size - snd_pcm_mmap_playback_avail(pcm);
-       else
-               d = snd_pcm_mmap_capture_avail(pcm);
-       *delayp = sd + d;
+       *delayp = sd + snd_pcm_mmap_delay(pcm);
        return 0;
 }
 
@@ -152,7 +149,7 @@ int snd_pcm_plugin_pause(snd_pcm_t *pcm, int enable)
 ssize_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, size_t frames)
 {
        snd_pcm_plugin_t *plugin = pcm->private;
-       ssize_t n = pcm->setup.buffer_size - snd_pcm_mmap_avail(pcm);
+       ssize_t n = snd_pcm_mmap_hw_avail(pcm);
        assert(n >= 0);
        if (n > 0) {
                if ((size_t)n > frames)
@@ -248,7 +245,7 @@ ssize_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, size_t client_size)
                size_t cont = pcm->setup.buffer_size - offset;
                if (cont < client_frames)
                        client_frames = cont;
-               err = plugin->write(pcm, pcm->mmap_areas, offset,
+               err = plugin->write(pcm, pcm->running_areas, offset,
                                    client_frames, &slave_frames);
                if (err < 0)
                        break;
@@ -286,7 +283,7 @@ ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
                size_t cont = pcm->setup.buffer_size - offset;
                if (cont < client_frames)
                        client_frames = cont;
-               err = plugin->read(pcm, pcm->mmap_areas, offset,
+               err = plugin->read(pcm, pcm->running_areas, offset,
                                   client_frames, &slave_frames);
                if (err < 0)
                        break;
index 48a5a8ea5b488fdb5c8c223e3ed834a762ce2f11..c2ef1796c252b70063c0eba0cfea05f8d9abef7a 100644 (file)
@@ -469,7 +469,7 @@ static ssize_t snd_pcm_rate_write_areas(snd_pcm_t *pcm,
                src_frames = client_size - client_xfer;
                dst_frames = snd_pcm_mmap_playback_xfer(slave, slave_size - slave_xfer);
                src_frames = rate->func(areas, client_offset, src_frames,
-                                       slave->mmap_areas, snd_pcm_mmap_offset(slave),
+                                       snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                                        &dst_frames, 
                                        pcm->setup.format.channels,
                                        rate->get_idx, rate->put_idx,
@@ -514,7 +514,7 @@ static ssize_t snd_pcm_rate_read_areas(snd_pcm_t *pcm,
                size_t src_frames, dst_frames;
                dst_frames = client_size - client_xfer;
                src_frames = snd_pcm_mmap_capture_xfer(slave, slave_size - slave_xfer);
-               src_frames = rate->func(slave->mmap_areas, snd_pcm_mmap_offset(slave),
+               src_frames = rate->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                                        src_frames,
                                        areas, client_offset, &dst_frames,
                                        pcm->setup.format.channels,
index 406f9f343c78af1185befe08b63a7aca1f32d6a6..08f9d43dbd47c992e97e2cdfb5d948a810d3cbd1 100644 (file)
@@ -572,7 +572,7 @@ static ssize_t snd_pcm_route_write_areas(snd_pcm_t *pcm,
        while (xfer < size) {
                size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
                route_transfer(areas, offset, 
-                              slave->mmap_areas, snd_pcm_mmap_offset(slave),
+                              snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                               frames, route->schannels, &route->params);
                err = snd_pcm_mmap_forward(slave, frames);
                if (err < 0)
@@ -600,14 +600,15 @@ static int snd_pcm_route_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *
                return err;
 #endif
        if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
-               setup->area.addr = pcm->mmap_data;
-               setup->area.first = setup->channel * pcm->bits_per_sample;
-               setup->area.step = pcm->bits_per_frame;
+               setup->running_area.addr = pcm->mmap_data;
+               setup->running_area.first = setup->channel * pcm->bits_per_sample;
+               setup->running_area.step = pcm->bits_per_frame;
        } else {
-               setup->area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
-               setup->area.first = 0;
-               setup->area.step = pcm->bits_per_sample;
+               setup->running_area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
+               setup->running_area.first = 0;
+               setup->running_area.step = pcm->bits_per_sample;
        }
+       setup->stopped_area = setup->running_area;
        return 0;
 }
 
@@ -626,7 +627,7 @@ static ssize_t snd_pcm_route_read_areas(snd_pcm_t *pcm,
        assert(size > 0);
        while (xfer < size) {
                size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
-               route_transfer(slave->mmap_areas, snd_pcm_mmap_offset(slave),
+               route_transfer(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                               areas, offset, 
                               frames, route->cchannels, &route->params);
                err = snd_pcm_mmap_forward(slave, frames);