summaryrefslogtreecommitdiff
path: root/src/pcm
diff options
context:
space:
mode:
Diffstat (limited to 'src/pcm')
-rw-r--r--src/pcm/pcm.c117
-rw-r--r--src/pcm/pcm_adpcm.c4
-rw-r--r--src/pcm/pcm_alaw.c4
-rw-r--r--src/pcm/pcm_copy.c4
-rw-r--r--src/pcm/pcm_file.c4
-rw-r--r--src/pcm/pcm_hooks.c4
-rw-r--r--src/pcm/pcm_hw.c11
-rw-r--r--src/pcm/pcm_ladspa.c4
-rw-r--r--src/pcm/pcm_lfloat.c4
-rw-r--r--src/pcm/pcm_linear.c4
-rw-r--r--src/pcm/pcm_local.h31
-rw-r--r--src/pcm/pcm_meter.c20
-rw-r--r--src/pcm/pcm_mmap.c38
-rw-r--r--src/pcm/pcm_mulaw.c4
-rw-r--r--src/pcm/pcm_multi.c4
-rw-r--r--src/pcm/pcm_null.c17
-rw-r--r--src/pcm/pcm_plug.c13
-rw-r--r--src/pcm/pcm_plugin.c16
-rw-r--r--src/pcm/pcm_rate.c4
-rw-r--r--src/pcm/pcm_route.c4
-rw-r--r--src/pcm/pcm_share.c42
-rw-r--r--src/pcm/pcm_shm.c160
22 files changed, 376 insertions, 137 deletions
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 3dc5f3b8..a6ac6ff1 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -1528,7 +1528,7 @@ ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, snd_pcm_sframes_t frames)
* \param bytes quantity in bytes
* \return quantity expressed in samples
*/
-int snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes)
+long snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes)
{
assert(pcm);
assert(pcm->setup);
@@ -1541,7 +1541,7 @@ int snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes)
* \param samples quantity in samples
* \return quantity expressed in bytes
*/
-ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, int samples)
+ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, long samples)
{
assert(pcm);
assert(pcm->setup);
@@ -5131,7 +5131,7 @@ int snd_pcm_mmap_begin(snd_pcm_t *pcm,
*areas = pcm->stopped_areas;
else
*areas = pcm->running_areas;
- *offset = *pcm->appl_ptr % pcm->buffer_size;
+ *offset = *pcm->appl.ptr % pcm->buffer_size;
cont = pcm->buffer_size - *offset;
f = *frames;
avail = snd_pcm_mmap_avail(pcm);
@@ -5202,7 +5202,7 @@ snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm,
snd_pcm_uframes_t frames)
{
assert(pcm);
- assert(offset == *pcm->appl_ptr % pcm->buffer_size);
+ assert(offset == *pcm->appl.ptr % pcm->buffer_size);
assert(frames <= snd_pcm_mmap_avail(pcm));
return pcm->fast_ops->mmap_commit(pcm->fast_op_arg, offset, frames);
}
@@ -5421,7 +5421,7 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area
snd_pcm_uframes_t _snd_pcm_mmap_hw_ptr(snd_pcm_t *pcm)
{
- return *pcm->hw_ptr;
+ return *pcm->hw.ptr;
}
snd_pcm_uframes_t _snd_pcm_boundary(snd_pcm_t *pcm)
@@ -5581,4 +5581,111 @@ int snd_pcm_conf_generic_id(const char *id)
return 0;
}
+static void snd_pcm_set_ptr(snd_pcm_t *pcm, snd_pcm_rbptr_t *rbptr,
+ volatile snd_pcm_uframes_t *hw_ptr, int fd, off_t offset)
+{
+ rbptr->master = NULL; /* I'm master */
+ rbptr->ptr = hw_ptr;
+ rbptr->fd = fd;
+ rbptr->offset = offset;
+ if (rbptr->changed)
+ rbptr->changed(pcm, NULL);
+}
+
+void snd_pcm_set_hw_ptr(snd_pcm_t *pcm, volatile snd_pcm_uframes_t *hw_ptr, int fd, off_t offset)
+{
+ assert(pcm);
+ assert(hw_ptr);
+ snd_pcm_set_ptr(pcm, &pcm->hw, hw_ptr, fd, offset);
+}
+
+void snd_pcm_set_appl_ptr(snd_pcm_t *pcm, volatile snd_pcm_uframes_t *appl_ptr, int fd, off_t offset)
+{
+ assert(pcm);
+ assert(appl_ptr);
+ snd_pcm_set_ptr(pcm, &pcm->appl, appl_ptr, fd, offset);
+}
+
+static void snd_pcm_link_ptr(snd_pcm_t *pcm, snd_pcm_rbptr_t *pcm_rbptr,
+ snd_pcm_t *slave, snd_pcm_rbptr_t *slave_rbptr)
+{
+ snd_pcm_t **a;
+ int idx;
+
+ a = slave_rbptr->link_dst;
+ for (idx = 0; idx < slave_rbptr->link_dst_count; idx++)
+ if (a[idx] == NULL) {
+ a[idx] = pcm;
+ goto __found_free_place;
+ }
+ a = realloc(a, sizeof(snd_pcm_t *) * (slave_rbptr->link_dst_count + 1));
+ if (a == NULL) {
+ pcm_rbptr->ptr = NULL;
+ pcm_rbptr->fd = -1;
+ pcm_rbptr->offset = 0UL;
+ return;
+ }
+ a[slave_rbptr->link_dst_count++] = pcm;
+ __found_free_place:
+ pcm_rbptr->master = slave_rbptr->master ? slave_rbptr->master : slave;
+ pcm_rbptr->ptr = slave_rbptr->ptr;
+ pcm_rbptr->fd = slave_rbptr->fd;
+ pcm_rbptr->offset = slave_rbptr->offset;
+ slave_rbptr->link_dst = a;
+ if (pcm_rbptr->changed)
+ pcm_rbptr->changed(pcm, slave);
+}
+
+static void snd_pcm_unlink_ptr(snd_pcm_t *pcm, snd_pcm_rbptr_t *pcm_rbptr,
+ snd_pcm_t *slave, snd_pcm_rbptr_t *slave_rbptr)
+{
+ snd_pcm_t **a;
+ int idx;
+
+ a = slave_rbptr->link_dst;
+ for (idx = 0; idx < slave_rbptr->link_dst_count; idx++)
+ if (a[idx] == pcm) {
+ a[idx] = NULL;
+ goto __found;
+ }
+ assert(0);
+ return;
+
+ __found:
+ pcm_rbptr->master = NULL;
+ pcm_rbptr->ptr = NULL;
+ pcm_rbptr->fd = -1;
+ pcm_rbptr->offset = 0UL;
+ if (pcm_rbptr->changed)
+ pcm_rbptr->changed(pcm, slave);
+}
+
+void snd_pcm_link_hw_ptr(snd_pcm_t *pcm, snd_pcm_t *slave)
+{
+ assert(pcm);
+ assert(slave);
+ snd_pcm_link_ptr(pcm, &pcm->hw, slave, &slave->hw);
+}
+
+void snd_pcm_link_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave)
+{
+ assert(pcm);
+ assert(slave);
+ snd_pcm_link_ptr(pcm, &pcm->appl, slave, &slave->appl);
+}
+
+void snd_pcm_unlink_hw_ptr(snd_pcm_t *pcm, snd_pcm_t *slave)
+{
+ assert(pcm);
+ assert(slave);
+ snd_pcm_unlink_ptr(pcm, &pcm->hw, slave, &slave->hw);
+}
+
+void snd_pcm_unlink_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave)
+{
+ assert(pcm);
+ assert(slave);
+ snd_pcm_unlink_ptr(pcm, &pcm->appl, slave, &slave->appl);
+}
+
#endif
diff --git a/src/pcm/pcm_adpcm.c b/src/pcm/pcm_adpcm.c
index 07471d7d..26061e5e 100644
--- a/src/pcm/pcm_adpcm.c
+++ b/src/pcm/pcm_adpcm.c
@@ -569,8 +569,8 @@ int snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfor
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = adpcm;
pcm->poll_fd = slave->poll_fd;
- pcm->hw_ptr = &adpcm->plug.hw_ptr;
- pcm->appl_ptr = &adpcm->plug.appl_ptr;
+ snd_pcm_set_hw_ptr(pcm, &adpcm->plug.hw_ptr, -1, 0);
+ snd_pcm_set_appl_ptr(pcm, &adpcm->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;
diff --git a/src/pcm/pcm_alaw.c b/src/pcm/pcm_alaw.c
index 0566395d..9a8c8470 100644
--- a/src/pcm/pcm_alaw.c
+++ b/src/pcm/pcm_alaw.c
@@ -442,8 +442,8 @@ int snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sform
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = alaw;
pcm->poll_fd = slave->poll_fd;
- pcm->hw_ptr = &alaw->plug.hw_ptr;
- pcm->appl_ptr = &alaw->plug.appl_ptr;
+ snd_pcm_set_hw_ptr(pcm, &alaw->plug.hw_ptr, -1, 0);
+ snd_pcm_set_appl_ptr(pcm, &alaw->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;
diff --git a/src/pcm/pcm_copy.c b/src/pcm/pcm_copy.c
index 37e6131d..e27cd937 100644
--- a/src/pcm/pcm_copy.c
+++ b/src/pcm/pcm_copy.c
@@ -205,8 +205,8 @@ int snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = copy;
pcm->poll_fd = slave->poll_fd;
- pcm->hw_ptr = &copy->plug.hw_ptr;
- pcm->appl_ptr = &copy->plug.appl_ptr;
+ snd_pcm_set_hw_ptr(pcm, &copy->plug.hw_ptr, -1, 0);
+ snd_pcm_set_appl_ptr(pcm, &copy->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;
diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index 6f12d59f..30536ba3 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -485,8 +485,8 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name,
pcm->fast_ops = &snd_pcm_file_fast_ops;
pcm->private_data = file;
pcm->poll_fd = slave->poll_fd;
- pcm->hw_ptr = slave->hw_ptr;
- pcm->appl_ptr = slave->appl_ptr;
+ snd_pcm_link_hw_ptr(pcm, slave);
+ snd_pcm_link_appl_ptr(pcm, slave);
*pcmp = pcm;
return 0;
diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c
index 6c204e17..946835de 100644
--- a/src/pcm/pcm_hooks.c
+++ b/src/pcm/pcm_hooks.c
@@ -344,8 +344,8 @@ int snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int
pcm->fast_ops = &snd_pcm_hooks_fast_ops;
pcm->private_data = h;
pcm->poll_fd = slave->poll_fd;
- pcm->hw_ptr = slave->hw_ptr;
- pcm->appl_ptr = slave->appl_ptr;
+ snd_pcm_link_hw_ptr(pcm, slave);
+ snd_pcm_link_appl_ptr(pcm, slave);
*pcmp = pcm;
return 0;
diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c
index d441fea8..aeb8d374 100644
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -29,6 +29,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stddef.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
@@ -60,7 +61,7 @@ typedef struct {
int fd;
int card, device, subdevice;
int mmap_emulation;
- volatile struct sndrv_pcm_mmap_status *mmap_status;
+ volatile struct sndrv_pcm_mmap_status * mmap_status;
struct sndrv_pcm_mmap_control *mmap_control;
int shadow_appl_ptr: 1,
avail_update_flag: 1,
@@ -256,10 +257,10 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
if (hw->mmap_shm) {
hw->shadow_appl_ptr = 1;
hw->appl_ptr = 0;
- pcm->appl_ptr = &hw->appl_ptr;
+ snd_pcm_set_appl_ptr(pcm, &hw->appl_ptr, -1, 0);
} else {
hw->shadow_appl_ptr = 0;
- pcm->appl_ptr = &hw->mmap_control->appl_ptr;
+ snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
}
}
return 0;
@@ -529,7 +530,7 @@ static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm)
return -errno;
}
hw->mmap_status = ptr;
- pcm->hw_ptr = &hw->mmap_status->hw_ptr;
+ snd_pcm_set_hw_ptr(pcm, &hw->mmap_status->hw_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_STATUS + offsetof(struct sndrv_pcm_mmap_status, hw_ptr));
return 0;
}
@@ -545,7 +546,7 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
return -errno;
}
hw->mmap_control = ptr;
- pcm->appl_ptr = &hw->mmap_control->appl_ptr;
+ snd_pcm_set_appl_ptr(pcm, &hw->mmap_control->appl_ptr, hw->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
return 0;
}
diff --git a/src/pcm/pcm_ladspa.c b/src/pcm/pcm_ladspa.c
index d932f0a2..0ef781e1 100644
--- a/src/pcm/pcm_ladspa.c
+++ b/src/pcm/pcm_ladspa.c
@@ -1173,8 +1173,8 @@ int snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name,
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = ladspa;
pcm->poll_fd = slave->poll_fd;
- pcm->hw_ptr = &ladspa->plug.hw_ptr;
- pcm->appl_ptr = &ladspa->plug.appl_ptr;
+ snd_pcm_set_hw_ptr(pcm, &ladspa->plug.hw_ptr, -1, 0);
+ snd_pcm_set_appl_ptr(pcm, &ladspa->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;
diff --git a/src/pcm/pcm_lfloat.c b/src/pcm/pcm_lfloat.c
index 6ff66f13..55aee134 100644
--- a/src/pcm/pcm_lfloat.c
+++ b/src/pcm/pcm_lfloat.c
@@ -407,8 +407,8 @@ int snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = lfloat;
pcm->poll_fd = slave->poll_fd;
- pcm->hw_ptr = &lfloat->plug.hw_ptr;
- pcm->appl_ptr = &lfloat->plug.appl_ptr;
+ snd_pcm_set_hw_ptr(pcm, &lfloat->plug.hw_ptr, -1, 0);
+ snd_pcm_set_appl_ptr(pcm, &lfloat->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;
diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c
index 4489cdb2..74aed8dc 100644
--- a/src/pcm/pcm_linear.c
+++ b/src/pcm/pcm_linear.c
@@ -346,8 +346,8 @@ int snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = linear;
pcm->poll_fd = slave->poll_fd;
- pcm->hw_ptr = &linear->plug.hw_ptr;
- pcm->appl_ptr = &linear->plug.appl_ptr;
+ snd_pcm_set_hw_ptr(pcm, &linear->plug.hw_ptr, -1, 0);
+ snd_pcm_set_appl_ptr(pcm, &linear->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;
diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h
index 7dddd4ed..aaf0a5de 100644
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -91,6 +91,17 @@ typedef enum sndrv_pcm_hw_param snd_pcm_hw_param_t;
/** device can do a kind of synchronized start */
#define SND_PCM_INFO_SYNC_START SNDRV_PCM_INFO_SYNC_START
+typedef struct _snd_pcm_rbptr {
+ snd_pcm_t *master;
+ volatile snd_pcm_uframes_t *ptr;
+ int fd;
+ off_t offset;
+ int link_dst_count;
+ snd_pcm_t **link_dst;
+ void *private_data;
+ void (*changed)(snd_pcm_t *pcm, snd_pcm_t *src);
+} snd_pcm_rbptr_t;
+
typedef struct _snd_pcm_channel_info {
unsigned int channel;
void *addr; /* base address of channel samples */
@@ -178,9 +189,9 @@ struct _snd_pcm {
snd_pcm_uframes_t buffer_size;
unsigned int sample_bits;
unsigned int frame_bits;
- snd_pcm_uframes_t *appl_ptr;
+ snd_pcm_rbptr_t appl;
+ snd_pcm_rbptr_t hw;
snd_pcm_uframes_t min_align;
- volatile snd_pcm_uframes_t *hw_ptr;
int mmap_rw;
snd_pcm_channel_info_t *mmap_channels;
snd_pcm_channel_area_t *running_areas;
@@ -207,6 +218,12 @@ int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid);
int snd_pcm_mmap(snd_pcm_t *pcm);
int snd_pcm_munmap(snd_pcm_t *pcm);
int snd_pcm_mmap_ready(snd_pcm_t *pcm);
+void snd_pcm_set_hw_ptr(snd_pcm_t *pcm, volatile snd_pcm_uframes_t *hw_ptr, int fd, off_t offset);
+void snd_pcm_set_appl_ptr(snd_pcm_t *pcm, volatile snd_pcm_uframes_t *appl_ptr, int fd, off_t offset);
+void snd_pcm_link_hw_ptr(snd_pcm_t *pcm, snd_pcm_t *slave);
+void snd_pcm_link_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave);
+void snd_pcm_unlink_hw_ptr(snd_pcm_t *pcm, snd_pcm_t *slave);
+void snd_pcm_unlink_appl_ptr(snd_pcm_t *pcm, snd_pcm_t *slave);
snd_pcm_sframes_t snd_pcm_mmap_appl_ptr(snd_pcm_t *pcm, off_t offset);
void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
@@ -238,7 +255,7 @@ int _snd_pcm_poll_descriptor(snd_pcm_t *pcm);
static inline snd_pcm_uframes_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
{
snd_pcm_sframes_t avail;
- avail = *pcm->hw_ptr + pcm->buffer_size - *pcm->appl_ptr;
+ avail = *pcm->hw.ptr + pcm->buffer_size - *pcm->appl.ptr;
if (avail < 0)
avail += pcm->boundary;
else if ((snd_pcm_uframes_t) avail >= pcm->boundary)
@@ -249,7 +266,7 @@ static inline snd_pcm_uframes_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
static inline snd_pcm_uframes_t snd_pcm_mmap_capture_avail(snd_pcm_t *pcm)
{
snd_pcm_sframes_t avail;
- avail = *pcm->hw_ptr - *pcm->appl_ptr;
+ avail = *pcm->hw.ptr - *pcm->appl.ptr;
if (avail < 0)
avail += pcm->boundary;
return avail;
@@ -276,7 +293,7 @@ static inline snd_pcm_sframes_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
static inline snd_pcm_sframes_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm)
{
snd_pcm_sframes_t avail;
- avail = *pcm->hw_ptr - *pcm->appl_ptr;
+ avail = *pcm->hw.ptr - *pcm->appl.ptr;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
avail += pcm->buffer_size;
if (avail < 0)
@@ -295,13 +312,13 @@ static inline const snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm)
static inline snd_pcm_uframes_t snd_pcm_mmap_offset(snd_pcm_t *pcm)
{
assert(pcm);
- return *pcm->appl_ptr % pcm->buffer_size;
+ return *pcm->appl.ptr % pcm->buffer_size;
}
static inline snd_pcm_uframes_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm)
{
assert(pcm);
- return *pcm->hw_ptr % pcm->buffer_size;
+ return *pcm->hw.ptr % pcm->buffer_size;
}
#define snd_pcm_mmap_playback_delay snd_pcm_mmap_playback_hw_avail
diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c
index 2775bc52..c3e41430 100644
--- a/src/pcm/pcm_meter.c
+++ b/src/pcm/pcm_meter.c
@@ -105,7 +105,7 @@ static void snd_pcm_meter_update_main(snd_pcm_t *pcm)
int locked;
locked = (pthread_mutex_trylock(&meter->update_mutex) >= 0);
areas = snd_pcm_mmap_areas(pcm);
- rptr = *pcm->hw_ptr;
+ rptr = *pcm->hw.ptr;
old_rptr = meter->rptr;
meter->rptr = rptr;
frames = rptr - old_rptr;
@@ -131,7 +131,7 @@ static int snd_pcm_meter_update_scope(snd_pcm_t *pcm)
pthread_mutex_lock(&meter->update_mutex);
areas = snd_pcm_mmap_areas(pcm);
_again:
- rptr = *pcm->hw_ptr;
+ rptr = *pcm->hw.ptr;
old_rptr = meter->rptr;
rmb();
if (atomic_read(&meter->reset)) {
@@ -333,9 +333,9 @@ static int snd_pcm_meter_prepare(snd_pcm_t *pcm)
err = snd_pcm_prepare(meter->slave);
if (err >= 0) {
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
- meter->rptr = *pcm->appl_ptr;
+ meter->rptr = *pcm->appl.ptr;
else
- meter->rptr = *pcm->hw_ptr;
+ meter->rptr = *pcm->hw.ptr;
}
return err;
}
@@ -346,7 +346,7 @@ static int snd_pcm_meter_reset(snd_pcm_t *pcm)
int err = snd_pcm_reset(meter->slave);
if (err >= 0) {
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
- meter->rptr = *pcm->appl_ptr;
+ meter->rptr = *pcm->appl.ptr;
}
return err;
}
@@ -386,7 +386,7 @@ static snd_pcm_sframes_t snd_pcm_meter_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t
snd_pcm_meter_t *meter = pcm->private_data;
snd_pcm_sframes_t err = snd_pcm_rewind(meter->slave, frames);
if (err > 0 && pcm->stream == SND_PCM_STREAM_PLAYBACK)
- meter->rptr = *pcm->appl_ptr;
+ meter->rptr = *pcm->appl.ptr;
return err;
}
@@ -401,13 +401,13 @@ static snd_pcm_sframes_t snd_pcm_meter_mmap_commit(snd_pcm_t *pcm,
snd_pcm_uframes_t size)
{
snd_pcm_meter_t *meter = pcm->private_data;
- snd_pcm_uframes_t old_rptr = *pcm->appl_ptr;
+ snd_pcm_uframes_t old_rptr = *pcm->appl.ptr;
snd_pcm_sframes_t result = snd_pcm_mmap_commit(meter->slave, offset, size);
if (result <= 0)
return result;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
snd_pcm_meter_add_frames(pcm, snd_pcm_mmap_areas(pcm), old_rptr, result);
- meter->rptr = *pcm->appl_ptr;
+ meter->rptr = *pcm->appl.ptr;
}
return result;
}
@@ -648,8 +648,8 @@ int snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, unsigned int frequenc
pcm->fast_ops = &snd_pcm_meter_fast_ops;
pcm->private_data = meter;
pcm->poll_fd = slave->poll_fd;
- pcm->hw_ptr = slave->hw_ptr;
- pcm->appl_ptr = slave->appl_ptr;
+ snd_pcm_link_hw_ptr(pcm, slave);
+ snd_pcm_link_appl_ptr(pcm, slave);
*pcmp = pcm;
pthread_mutex_init(&meter->update_mutex, NULL);
diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c
index d5d2d0c6..63c05056 100644
--- a/src/pcm/pcm_mmap.c
+++ b/src/pcm/pcm_mmap.c
@@ -36,48 +36,66 @@ size_t page_size(void)
size_t page_align(size_t size)
{
size_t r;
- long psz = sysconf(_SC_PAGE_SIZE);
- assert(psz > 0);
+ long psz = page_size();
r = size % psz;
if (r)
return size + psz - r;
return size;
}
+size_t page_ptr(size_t object_offset, size_t object_size, size_t *offset, size_t *mmap_offset)
+{
+ size_t r;
+ long psz = page_size();
+ assert(offset);
+ assert(mmap_offset);
+ *mmap_offset = object_offset;
+ object_offset %= psz;
+ *mmap_offset -= object_offset;
+ object_size += object_offset;
+ r = object_size % psz;
+ if (r)
+ r = object_size + psz - r;
+ else
+ r = object_size;
+ *offset = object_offset;
+ return r;
+}
+
void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
- snd_pcm_sframes_t appl_ptr = *pcm->appl_ptr;
+ snd_pcm_sframes_t appl_ptr = *pcm->appl.ptr;
appl_ptr -= frames;
if (appl_ptr < 0)
appl_ptr += pcm->boundary;
- *pcm->appl_ptr = appl_ptr;
+ *pcm->appl.ptr = appl_ptr;
}
void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
- snd_pcm_uframes_t appl_ptr = *pcm->appl_ptr;
+ snd_pcm_uframes_t appl_ptr = *pcm->appl.ptr;
appl_ptr += frames;
if (appl_ptr >= pcm->boundary)
appl_ptr -= pcm->boundary;
- *pcm->appl_ptr = appl_ptr;
+ *pcm->appl.ptr = appl_ptr;
}
void snd_pcm_mmap_hw_backward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
- snd_pcm_sframes_t hw_ptr = *pcm->hw_ptr;
+ snd_pcm_sframes_t hw_ptr = *pcm->hw.ptr;
hw_ptr -= frames;
if (hw_ptr < 0)
hw_ptr += pcm->boundary;
- *pcm->hw_ptr = hw_ptr;
+ *pcm->hw.ptr = hw_ptr;
}
void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
- snd_pcm_uframes_t hw_ptr = *pcm->hw_ptr;
+ snd_pcm_uframes_t hw_ptr = *pcm->hw.ptr;
hw_ptr += frames;
if (hw_ptr >= pcm->boundary)
hw_ptr -= pcm->boundary;
- *pcm->hw_ptr = hw_ptr;
+ *pcm->hw.ptr = hw_ptr;
}
static snd_pcm_sframes_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm,
diff --git a/src/pcm/pcm_mulaw.c b/src/pcm/pcm_mulaw.c
index d6b53047..53b4d319 100644
--- a/src/pcm/pcm_mulaw.c
+++ b/src/pcm/pcm_mulaw.c
@@ -457,8 +457,8 @@ int snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfor
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = mulaw;
pcm->poll_fd = slave->poll_fd;
- pcm->hw_ptr = &mulaw->plug.hw_ptr;
- pcm->appl_ptr = &mulaw->plug.appl_ptr;
+ snd_pcm_set_hw_ptr(pcm, &mulaw->plug.hw_ptr, -1, 0);
+ snd_pcm_set_appl_ptr(pcm, &mulaw->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;
diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c
index 59197f33..7f5caac6 100644
--- a/src/pcm/pcm_multi.c
+++ b/src/pcm/pcm_multi.c
@@ -690,8 +690,8 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name,
pcm->fast_ops = &snd_pcm_multi_fast_ops;
pcm->private_data = multi;
pcm->poll_fd = multi->slaves[master_slave].pcm->poll_fd;
- pcm->hw_ptr = multi->slaves[master_slave].pcm->hw_ptr;
- pcm->appl_ptr = multi->slaves[master_slave].pcm->appl_ptr;
+ snd_pcm_link_hw_ptr(pcm, multi->slaves[master_slave].pcm);
+ snd_pcm_link_appl_ptr(pcm, multi->slaves[master_slave].pcm);
*pcmp = pcm;
return 0;
}
diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c
index c5f3e70e..253606a8 100644
--- a/src/pcm/pcm_null.c
+++ b/src/pcm/pcm_null.c
@@ -112,16 +112,15 @@ static int snd_pcm_null_prepare(snd_pcm_t *pcm)
{
snd_pcm_null_t *null = pcm->private_data;
null->state = SND_PCM_STATE_PREPARED;
- null->appl_ptr = 0;
- null->hw_ptr = 0;
+ *pcm->appl.ptr = 0;
+ *pcm->hw.ptr = 0;
return 0;
}
static int snd_pcm_null_reset(snd_pcm_t *pcm)
{
- snd_pcm_null_t *null = pcm->private_data;
- null->appl_ptr = 0;
- null->hw_ptr = 0;
+ *pcm->appl.ptr = 0;
+ *pcm->hw.ptr = 0;
return 0;
}
@@ -131,9 +130,9 @@ static int snd_pcm_null_start(snd_pcm_t *pcm)
assert(null->state == SND_PCM_STATE_PREPARED);
null->state = SND_PCM_STATE_RUNNING;
if (pcm->stream == SND_PCM_STREAM_CAPTURE)
- *pcm->hw_ptr = *pcm->appl_ptr + pcm->buffer_size;
+ *pcm->hw.ptr = *pcm->appl.ptr + pcm->buffer_size;
else
- *pcm->hw_ptr = *pcm->appl_ptr;
+ *pcm->hw.ptr = *pcm->appl.ptr;
return 0;
}
@@ -387,8 +386,8 @@ int snd_pcm_null_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t strea
pcm->fast_ops = &snd_pcm_null_fast_ops;
pcm->private_data = null;
pcm->poll_fd = fd;
- pcm->hw_ptr = &null->hw_ptr;
- pcm->appl_ptr = &null->appl_ptr;
+ snd_pcm_set_hw_ptr(pcm, &null->hw_ptr, -1, 0);
+ snd_pcm_set_appl_ptr(pcm, &null->appl_ptr, -1, 0);
*pcmp = pcm;
return 0;
diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c
index 86d838c3..d3fe50fb 100644
--- a/src/pcm/pcm_plug.c
+++ b/src/pcm/pcm_plug.c
@@ -832,8 +832,10 @@ static int snd_pcm_plug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
snd_pcm_plug_clear(pcm);
return err;
}
- pcm->hw_ptr = slave->hw_ptr;
- pcm->appl_ptr = slave->appl_ptr;
+ snd_pcm_unlink_hw_ptr(pcm, plug->req_slave);
+ snd_pcm_unlink_appl_ptr(pcm, plug->req_slave);
+ snd_pcm_link_hw_ptr(pcm, slave);
+ snd_pcm_link_appl_ptr(pcm, slave);
return 0;
}
@@ -915,6 +917,7 @@ int snd_pcm_plug_open(snd_pcm_t **pcmp,
snd_pcm_plug_t *plug;
int err;
assert(pcmp && slave);
+
plug = calloc(1, sizeof(snd_pcm_plug_t));
if (!plug)
return -ENOMEM;
@@ -939,8 +942,8 @@ int snd_pcm_plug_open(snd_pcm_t **pcmp,
pcm->fast_op_arg = slave->fast_op_arg;
pcm->private_data = plug;
pcm->poll_fd = slave->poll_fd;
- pcm->hw_ptr = slave->hw_ptr;
- pcm->appl_ptr = slave->appl_ptr;
+ snd_pcm_link_hw_ptr(pcm, slave);
+ snd_pcm_link_appl_ptr(pcm, slave);
*pcmp = pcm;
return 0;
@@ -1084,7 +1087,7 @@ int _snd_pcm_plug_open(snd_pcm_t **pcmp, const char *name,
return err;
}
}
-
+
err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
snd_config_delete(sconf);
if (err < 0)
diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c
index bc52233e..2aa6b3ee 100644
--- a/src/pcm/pcm_plugin.c
+++ b/src/pcm/pcm_plugin.c
@@ -211,8 +211,8 @@ int snd_pcm_plugin_prepare(snd_pcm_t *pcm)
snd_atomic_write_end(&plugin->watom);
return err;
}
- plugin->hw_ptr = 0;
- plugin->appl_ptr = 0;
+ *pcm->hw.ptr = 0;
+ *pcm->appl.ptr = 0;
snd_atomic_write_end(&plugin->watom);
if (plugin->init) {
err = plugin->init(pcm);
@@ -232,8 +232,8 @@ static int snd_pcm_plugin_reset(snd_pcm_t *pcm)
snd_atomic_write_end(&plugin->watom);
return err;
}
- plugin->hw_ptr = 0;
- plugin->appl_ptr = 0;
+ *pcm->hw.ptr = 0;
+ *pcm->appl.ptr = 0;
snd_atomic_write_end(&plugin->watom);
if (plugin->init) {
err = plugin->init(pcm);
@@ -504,12 +504,12 @@ snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED)
goto _capture;
if (plugin->client_frames) {
- plugin->hw_ptr = plugin->client_frames(pcm, *slave->hw_ptr);
+ *pcm->hw.ptr = plugin->client_frames(pcm, *slave->hw.ptr);
if (slave_size <= 0)
return slave_size;
return plugin->client_frames(pcm, slave_size);
} else {
- plugin->hw_ptr = *slave->hw_ptr;
+ *pcm->hw.ptr = *slave->hw.ptr;
return slave_size;
}
_capture:
@@ -599,8 +599,8 @@ int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
snd_atomic_read_ok(&ratom);
return err;
}
- status->appl_ptr = plugin->appl_ptr;
- status->hw_ptr = plugin->hw_ptr;
+ status->appl_ptr = *pcm->appl.ptr;
+ status->hw_ptr = *pcm->hw.ptr;
status->avail = pcm->buffer_size;
snd_pcm_plugin_delay(pcm, &status->delay);
if (!snd_atomic_read_ok(&ratom)) {
diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c
index 752c3af9..5273d7dc 100644
--- a/src/pcm/pcm_rate.c
+++ b/src/pcm/pcm_rate.c
@@ -593,8 +593,8 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sform
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = rate;
pcm->poll_fd = slave->poll_fd;
- pcm->hw_ptr = &rate->plug.hw_ptr;
- pcm->appl_ptr = &rate->plug.appl_ptr;
+ snd_pcm_set_hw_ptr(pcm, &rate->plug.hw_ptr, -1, 0);
+ snd_pcm_set_appl_ptr(pcm, &rate->plug.appl_ptr, -1, 0);
*pcmp = pcm;
return 0;
diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c
index 2b328a42..2c492c31 100644
--- a/src/pcm/pcm_route.c
+++ b/src/pcm/pcm_route.c
@@ -800,8 +800,8 @@ int snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
pcm->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = route;
pcm->poll_fd = slave->poll_fd;
- pcm->hw_ptr = &route->plug.hw_ptr;
- pcm->appl_ptr = &route->plug.appl_ptr;
+ snd_pcm_set_hw_ptr(pcm, &route->plug.hw_ptr, -1, 0);
+ snd_pcm_set_appl_ptr(pcm, &route->plug.appl_ptr, -1, 0);
err = route_load_ttable(&route->params, pcm->stream, tt_ssize, ttable, tt_cused, tt_sused);
if (err < 0) {
snd_pcm_close(pcm);
diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c
index 40f4a8d3..89a1c4f4 100644
--- a/src/pcm/pcm_share.c
+++ b/src/pcm/pcm_share.c
@@ -123,7 +123,7 @@ static snd_pcm_uframes_t snd_pcm_share_slave_avail(snd_pcm_share_slave_t *slave)
{
snd_pcm_sframes_t avail;
snd_pcm_t *pcm = slave->pcm;
- avail = slave->hw_ptr - *pcm->appl_ptr;
+ avail = slave->hw_ptr - *pcm->appl.ptr;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
avail += pcm->buffer_size;
if (avail < 0)
@@ -147,7 +147,7 @@ static snd_pcm_uframes_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *sla
buffer_size = slave->pcm->buffer_size;
min_frames = slave_avail;
max_frames = 0;
- slave_appl_ptr = *slave->pcm->appl_ptr;
+ slave_appl_ptr = *slave->pcm->appl.ptr;
list_for_each(i, &slave->clients) {
snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
snd_pcm_t *pcm = share->pcm;
@@ -336,7 +336,7 @@ static snd_pcm_uframes_t _snd_pcm_share_slave_missing(snd_pcm_share_slave_t *sla
snd_pcm_uframes_t missing = INT_MAX;
struct list_head *i;
/* snd_pcm_sframes_t avail = */ snd_pcm_avail_update(slave->pcm);
- slave->hw_ptr = *slave->pcm->hw_ptr;
+ slave->hw_ptr = *slave->pcm->hw.ptr;
list_for_each(i, &slave->clients) {
snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
snd_pcm_t *pcm = share->pcm;
@@ -353,6 +353,7 @@ static void *snd_pcm_share_thread(void *data)
snd_pcm_t *spcm = slave->pcm;
struct pollfd pfd[2];
int err;
+
pfd[0].fd = slave->poll[0];
pfd[0].events = POLLIN;
err = snd_pcm_poll_descriptors(spcm, &pfd[1], 1);
@@ -373,7 +374,7 @@ static void *snd_pcm_share_thread(void *data)
if (hw_ptr >= spcm->boundary)
hw_ptr -= spcm->boundary;
hw_ptr -= hw_ptr % spcm->period_size;
- avail_min = hw_ptr - *spcm->appl_ptr;
+ avail_min = hw_ptr - *spcm->appl.ptr;
if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
avail_min += spcm->buffer_size;
if (avail_min < 0)
@@ -408,7 +409,7 @@ static void _snd_pcm_share_update(snd_pcm_t *pcm)
snd_pcm_t *spcm = slave->pcm;
snd_pcm_uframes_t missing;
/* snd_pcm_sframes_t avail = */ snd_pcm_avail_update(spcm);
- slave->hw_ptr = *slave->pcm->hw_ptr;
+ slave->hw_ptr = *slave->pcm->hw.ptr;
missing = _snd_pcm_share_missing(pcm);
// printf("missing %ld\n", missing);
if (!slave->polling) {
@@ -423,7 +424,7 @@ static void _snd_pcm_share_update(snd_pcm_t *pcm)
if (hw_ptr >= spcm->boundary)
hw_ptr -= spcm->boundary;
hw_ptr -= hw_ptr % spcm->period_size;
- avail_min = hw_ptr - *spcm->appl_ptr;
+ avail_min = hw_ptr - *spcm->appl.ptr;
if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
avail_min += spcm->buffer_size;
if (avail_min < 0)
@@ -760,7 +761,7 @@ static snd_pcm_sframes_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
Pthread_mutex_unlock(&slave->mutex);
return avail;
}
- share->hw_ptr = *slave->pcm->hw_ptr;
+ share->hw_ptr = *slave->pcm->hw.ptr;
}
Pthread_mutex_unlock(&slave->mutex);
avail = snd_pcm_mmap_avail(pcm);
@@ -781,7 +782,7 @@ static snd_pcm_sframes_t _snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
snd_pcm_sframes_t frames;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
share->state == SND_PCM_STATE_RUNNING) {
- frames = *spcm->appl_ptr - share->appl_ptr;
+ frames = *spcm->appl.ptr - share->appl_ptr;
if (frames > (snd_pcm_sframes_t)pcm->buffer_size)
frames -= pcm->boundary;
else if (frames < -(snd_pcm_sframes_t)pcm->buffer_size)
@@ -860,7 +861,7 @@ static int snd_pcm_share_reset(snd_pcm_t *pcm)
/* FIXME? */
Pthread_mutex_lock(&slave->mutex);
snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels, pcm->buffer_size, pcm->format);
- share->hw_ptr = *slave->pcm->hw_ptr;
+ share->hw_ptr = *slave->pcm->hw.ptr;
share->appl_ptr = share->hw_ptr;
Pthread_mutex_unlock(&slave->mutex);
return err;
@@ -893,8 +894,8 @@ static int snd_pcm_share_start(snd_pcm_t *pcm)
goto _end;
}
assert(share->hw_ptr == 0);
- share->hw_ptr = *spcm->hw_ptr;
- share->appl_ptr = *spcm->appl_ptr;
+ share->hw_ptr = *spcm->hw.ptr;
+ share->appl_ptr = *spcm->appl.ptr;
while (xfer < hw_avail) {
snd_pcm_uframes_t frames = hw_avail - xfer;
snd_pcm_uframes_t offset = snd_pcm_mmap_offset(pcm);
@@ -1142,6 +1143,7 @@ static int snd_pcm_share_close(snd_pcm_t *pcm)
snd_pcm_share_t *share = pcm->private_data;
snd_pcm_share_slave_t *slave = share->slave;
int err = 0;
+
Pthread_mutex_lock(&snd_pcm_share_slaves_mutex);
Pthread_mutex_lock(&slave->mutex);
slave->open_count--;
@@ -1353,7 +1355,9 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname,
free(share);
return err;
}
- slave = calloc(1, sizeof(*slave));
+ /* FIXME: bellow is a real ugly hack to get things working */
+ /* there is a memory leak somewhere, but I'm unable to trace it --jk */
+ slave = calloc(1, sizeof(snd_pcm_share_slave_t) * 8);
if (!slave) {
Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex);
snd_pcm_close(spcm);
@@ -1408,8 +1412,8 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname,
pcm->fast_ops = &snd_pcm_share_fast_ops;
pcm->private_data = share;
pcm->poll_fd = share->client_socket;
- pcm->hw_ptr = &share->hw_ptr;
- pcm->appl_ptr = &share->appl_ptr;
+ snd_pcm_set_hw_ptr(pcm, &share->hw_ptr, -1, 0);
+ snd_pcm_set_appl_ptr(pcm, &share->appl_ptr, -1, 0);
slave->open_count++;
list_add_tail(&share->list, &slave->clients);
@@ -1424,7 +1428,11 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname,
\section pcm_plugins_share Plugin: Share
-This plugin allows sharing of multiple channels with more clients.
+This plugin allows sharing of multiple channels with more clients. The access
+to each channel is exlusive (samples are not mixed together). It means, if
+the channel zero is used with first client, the channel cannot be used with
+second one. If you are looking for a mixing plugin, use the
+\ref pcm_plugins_smix "smix plugin".
\code
pcm.name {
@@ -1433,8 +1441,6 @@ pcm.name {
# or
slave { # Slave definition
pcm STR # Slave PCM name
- # or
- pcm { } # Slave PCM definition
}
bindings {
N INT # Slave channel INT for client channel N
@@ -1520,7 +1526,7 @@ int _snd_pcm_share_open(snd_pcm_t **pcmp, const char *name,
err = snd_config_get_string(sconf, &sname);
sname = err >= 0 && sname ? strdup(sname) : NULL;
snd_config_delete(sconf);
- if (err < 0) {
+ if (sname == NULL) {
SNDERR("slave.pcm is not a string");
return err;
}
diff --git a/src/pcm/pcm_shm.c b/src/pcm/pcm_shm.c
index e5ab2707..fe91afbd 100644
--- a/src/pcm/pcm_shm.c
+++ b/src/pcm/pcm_shm.c
@@ -60,49 +60,50 @@ typedef struct {
#ifndef DOC_HIDDEN
int receive_fd(int sock, void *data, size_t len, int *fd)
{
- int ret;
- size_t cmsg_len = CMSG_LEN(sizeof(int));
- struct cmsghdr *cmsg = alloca(cmsg_len);
- int *fds = (int *) CMSG_DATA(cmsg);
- struct msghdr msghdr;
- struct iovec vec;
-
- vec.iov_base = (void *)&data;
- vec.iov_len = len;
-
- cmsg->cmsg_len = cmsg_len;
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- *fds = -1;
-
- msghdr.msg_name = NULL;
- msghdr.msg_namelen = 0;
- msghdr.msg_iov = &vec;
- msghdr.msg_iovlen = 1;
- msghdr.msg_control = cmsg;
- msghdr.msg_controllen = cmsg_len;
- msghdr.msg_flags = 0;
-
- ret = recvmsg(sock, &msghdr, 0);
- if (ret < 0) {
- SYSERR("recvmsg failed");
- return -errno;
- }
- *fd = *fds;
- return ret;
+ int ret;
+ size_t cmsg_len = CMSG_LEN(sizeof(int));
+ struct cmsghdr *cmsg = alloca(cmsg_len);
+ int *fds = (int *) CMSG_DATA(cmsg);
+ struct msghdr msghdr;
+ struct iovec vec;
+
+ vec.iov_base = (void *)&data;
+ vec.iov_len = len;
+
+ cmsg->cmsg_len = cmsg_len;
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ *fds = -1;
+
+ msghdr.msg_name = NULL;
+ msghdr.msg_namelen = 0;
+ msghdr.msg_iov = &vec;
+ msghdr.msg_iovlen = 1;
+ msghdr.msg_control = cmsg;
+ msghdr.msg_controllen = cmsg_len;
+ msghdr.msg_flags = 0;
+
+ ret = recvmsg(sock, &msghdr, 0);
+ if (ret < 0) {
+ SYSERR("recvmsg failed");
+ return -errno;
+ }
+ *fd = *fds;
+ return ret;
}
#endif
-static long snd_pcm_shm_action(snd_pcm_t *pcm)
+static long snd_pcm_shm_action_fd0(snd_pcm_t *pcm, int *fd)
{
snd_pcm_shm_t *shm = pcm->private_data;
int err;
char buf[1];
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
+
err = write(shm->socket, buf, 1);
if (err != 1)
return -EBADFD;
- err = read(shm->socket, buf, 1);
+ err = receive_fd(shm->socket, buf, 1, fd);
if (err != 1)
return -EBADFD;
if (ctrl->cmd) {
@@ -112,12 +113,82 @@ static long snd_pcm_shm_action(snd_pcm_t *pcm)
return ctrl->result;
}
+static int snd_pcm_shm_new_rbptr(snd_pcm_t *pcm, snd_pcm_shm_t *shm,
+ snd_pcm_rbptr_t *rbptr, volatile snd_pcm_shm_rbptr_t *shm_rbptr)
+{
+ if (!shm_rbptr->use_mmap) {
+ if (&pcm->hw == rbptr)
+ snd_pcm_set_hw_ptr(pcm, &shm_rbptr->ptr, -1, 0);
+ else
+ snd_pcm_set_appl_ptr(pcm, &shm_rbptr->ptr, -1, 0);
+ } else {
+ void *ptr;
+ size_t mmap_size, mmap_offset, offset;
+ int fd;
+ long result;
+
+ shm->ctrl->cmd = &pcm->hw == rbptr ? SND_PCM_IOCTL_HW_PTR_FD : SND_PCM_IOCTL_APPL_PTR_FD;
+ result = snd_pcm_shm_action_fd0(pcm, &fd);
+ if (result < 0)
+ return result;
+ mmap_size = page_ptr(shm_rbptr->offset, sizeof(snd_pcm_uframes_t), &offset, &mmap_offset);
+ ptr = mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, mmap_offset);
+ if (ptr == MAP_FAILED || ptr == NULL) {
+ SYSERR("shm rbptr mmap failed");
+ return -errno;
+ }
+ if (&pcm->hw == rbptr)
+ snd_pcm_set_hw_ptr(pcm, (snd_pcm_uframes_t *)((char *)ptr + offset), fd, shm_rbptr->offset);
+ else
+ snd_pcm_set_appl_ptr(pcm, (snd_pcm_uframes_t *)((char *)ptr + offset), fd, shm_rbptr->offset);
+ }
+ return 0;
+}
+
+static long snd_pcm_shm_action(snd_pcm_t *pcm)
+{
+ snd_pcm_shm_t *shm = pcm->private_data;
+ int err, result;
+ char buf[1];
+ volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
+
+ if (ctrl->hw.changed || ctrl->appl.changed)
+ return -EBADFD;
+ err = write(shm->socket, buf, 1);
+ if (err != 1)
+ return -EBADFD;
+ err = read(shm->socket, buf, 1);
+ if (err != 1)
+ return -EBADFD;
+ if (ctrl->cmd) {
+ SNDERR("Server has not done the cmd");
+ return -EBADFD;
+ }
+ result = ctrl->result;
+ if (ctrl->hw.changed) {
+ err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->hw, &ctrl->hw);
+ if (err < 0)
+ return err;
+ ctrl->hw.changed = 0;
+ }
+ if (ctrl->appl.changed) {
+ err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->appl, &ctrl->appl);
+ if (err < 0)
+ return err;
+ ctrl->appl.changed = 0;
+ }
+ return result;
+}
+
static long snd_pcm_shm_action_fd(snd_pcm_t *pcm, int *fd)
{
snd_pcm_shm_t *shm = pcm->private_data;
int err;
char buf[1];
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
+
+ if (ctrl->hw.changed || ctrl->appl.changed)
+ return -EBADFD;
err = write(shm->socket, buf, 1);
if (err != 1)
return -EBADFD;
@@ -128,6 +199,18 @@ static long snd_pcm_shm_action_fd(snd_pcm_t *pcm, int *fd)
SNDERR("Server has not done the cmd");
return -EBADFD;
}
+ if (ctrl->hw.changed) {
+ err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->hw, &ctrl->hw);
+ if (err < 0)
+ return err;
+ ctrl->hw.changed = 0;
+ }
+ if (ctrl->appl.changed) {
+ err = snd_pcm_shm_new_rbptr(pcm, shm, &pcm->appl, &ctrl->appl);
+ if (err < 0)
+ return err;
+ ctrl->appl.changed = 0;
+ }
return ctrl->result;
}
@@ -422,8 +505,13 @@ static int snd_pcm_shm_drain(snd_pcm_t *pcm)
snd_pcm_shm_t *shm = pcm->private_data;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
int err;
- ctrl->cmd = SNDRV_PCM_IOCTL_DRAIN;
- err = snd_pcm_shm_action(pcm);
+ do {
+ ctrl->cmd = SNDRV_PCM_IOCTL_DRAIN;
+ err = snd_pcm_shm_action(pcm);
+ if (err != -EAGAIN)
+ break;
+ usleep(10000);
+ } while (1);
if (err < 0)
return err;
if (!(pcm->mode & SND_PCM_NONBLOCK))
@@ -691,8 +779,8 @@ int snd_pcm_shm_open(snd_pcm_t **pcmp, const char *name,
return err;
}
pcm->poll_fd = err;
- pcm->hw_ptr = &ctrl->hw_ptr;
- pcm->appl_ptr = &ctrl->appl_ptr;
+ snd_pcm_set_hw_ptr(pcm, &ctrl->hw.ptr, -1, 0);
+ snd_pcm_set_appl_ptr(pcm, &ctrl->appl.ptr, -1, 0);
*pcmp = pcm;
return 0;