mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Moved ring buffer pointers and added a mechanism to transfer them via shm
This commit is contained in:
parent
f063381430
commit
c941c548f8
26 changed files with 469 additions and 171 deletions
|
|
@ -271,6 +271,44 @@ static int pcm_handler(waiter_t *waiter, unsigned short events)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void pcm_shm_hw_ptr_changed(snd_pcm_t *pcm, snd_pcm_t *src ATTRIBUTE_UNUSED)
|
||||
{
|
||||
client_t *client = pcm->hw.private_data;
|
||||
volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
|
||||
snd_pcm_t *loop;
|
||||
|
||||
ctrl->hw.changed = 1;
|
||||
if (pcm->hw.fd >= 0) {
|
||||
ctrl->hw.use_mmap = 1;
|
||||
ctrl->hw.offset = pcm->hw.offset;
|
||||
return;
|
||||
}
|
||||
ctrl->hw.use_mmap = 0;
|
||||
ctrl->hw.ptr = pcm->hw.ptr ? *pcm->hw.ptr : 0;
|
||||
for (loop = pcm->hw.master; loop; loop = loop->hw.master)
|
||||
loop->hw.ptr = &ctrl->hw.ptr;
|
||||
pcm->hw.ptr = &ctrl->hw.ptr;
|
||||
}
|
||||
|
||||
static void pcm_shm_appl_ptr_changed(snd_pcm_t *pcm, snd_pcm_t *src ATTRIBUTE_UNUSED)
|
||||
{
|
||||
client_t *client = pcm->appl.private_data;
|
||||
volatile snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
|
||||
snd_pcm_t *loop;
|
||||
|
||||
ctrl->appl.changed = 1;
|
||||
if (pcm->appl.fd >= 0) {
|
||||
ctrl->appl.use_mmap = 1;
|
||||
ctrl->appl.offset = pcm->appl.offset;
|
||||
return;
|
||||
}
|
||||
ctrl->appl.use_mmap = 0;
|
||||
ctrl->appl.ptr = pcm->appl.ptr ? *pcm->appl.ptr : 0;
|
||||
for (loop = pcm->appl.master; loop; loop = loop->appl.master)
|
||||
loop->appl.ptr = &ctrl->appl.ptr;
|
||||
pcm->appl.ptr = &ctrl->appl.ptr;
|
||||
}
|
||||
|
||||
static int pcm_shm_open(client_t *client, int *cookie)
|
||||
{
|
||||
int shmid;
|
||||
|
|
@ -282,6 +320,10 @@ static int pcm_shm_open(client_t *client, int *cookie)
|
|||
return err;
|
||||
client->device.pcm.handle = pcm;
|
||||
client->device.pcm.fd = _snd_pcm_poll_descriptor(pcm);
|
||||
pcm->hw.private_data = client;
|
||||
pcm->hw.changed = pcm_shm_hw_ptr_changed;
|
||||
pcm->appl.private_data = client;
|
||||
pcm->appl.changed = pcm_shm_appl_ptr_changed;
|
||||
|
||||
shmid = shmget(IPC_PRIVATE, PCM_SHM_SIZE, 0666);
|
||||
if (shmid < 0) {
|
||||
|
|
@ -361,6 +403,13 @@ static int shm_ack_fd(client_t *client, int fd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int shm_rbptr_fd(client_t *client, snd_pcm_rbptr_t *rbptr)
|
||||
{
|
||||
if (rbptr->fd < 0)
|
||||
return -EINVAL;
|
||||
return shm_ack_fd(client, rbptr->fd);
|
||||
}
|
||||
|
||||
static void async_handler(snd_async_handler_t *handler)
|
||||
{
|
||||
client_t *client = snd_async_handler_get_callback_private(handler);
|
||||
|
|
@ -424,22 +473,15 @@ static int pcm_shm_cmd(client_t *client)
|
|||
break;
|
||||
case SND_PCM_IOCTL_AVAIL_UPDATE:
|
||||
ctrl->result = snd_pcm_avail_update(pcm);
|
||||
ctrl->hw_ptr = *pcm->hw_ptr;
|
||||
break;
|
||||
case SNDRV_PCM_IOCTL_PREPARE:
|
||||
ctrl->result = snd_pcm_prepare(pcm);
|
||||
ctrl->appl_ptr = *pcm->appl_ptr;
|
||||
ctrl->hw_ptr = *pcm->hw_ptr;
|
||||
break;
|
||||
case SNDRV_PCM_IOCTL_RESET:
|
||||
ctrl->result = snd_pcm_reset(pcm);
|
||||
ctrl->appl_ptr = *pcm->appl_ptr;
|
||||
ctrl->hw_ptr = *pcm->hw_ptr;
|
||||
break;
|
||||
case SNDRV_PCM_IOCTL_START:
|
||||
ctrl->result = snd_pcm_start(pcm);
|
||||
ctrl->appl_ptr = *pcm->appl_ptr;
|
||||
ctrl->hw_ptr = *pcm->hw_ptr;
|
||||
break;
|
||||
case SNDRV_PCM_IOCTL_DRAIN:
|
||||
ctrl->result = snd_pcm_drain(pcm);
|
||||
|
|
@ -458,7 +500,6 @@ static int pcm_shm_cmd(client_t *client)
|
|||
break;
|
||||
case SNDRV_PCM_IOCTL_REWIND:
|
||||
ctrl->result = snd_pcm_rewind(pcm, ctrl->u.rewind.frames);
|
||||
ctrl->appl_ptr = *pcm->appl_ptr;
|
||||
break;
|
||||
case SNDRV_PCM_IOCTL_LINK:
|
||||
{
|
||||
|
|
@ -485,7 +526,6 @@ static int pcm_shm_cmd(client_t *client)
|
|||
ctrl->result = snd_pcm_mmap_commit(pcm,
|
||||
ctrl->u.mmap_commit.offset,
|
||||
ctrl->u.mmap_commit.frames);
|
||||
ctrl->appl_ptr = *pcm->appl_ptr;
|
||||
break;
|
||||
case SND_PCM_IOCTL_POLL_DESCRIPTOR:
|
||||
ctrl->result = 0;
|
||||
|
|
@ -493,6 +533,10 @@ static int pcm_shm_cmd(client_t *client)
|
|||
case SND_PCM_IOCTL_CLOSE:
|
||||
client->ops->close(client);
|
||||
break;
|
||||
case SND_PCM_IOCTL_HW_PTR_FD:
|
||||
return shm_rbptr_fd(client, &pcm->hw);
|
||||
case SND_PCM_IOCTL_APPL_PTR_FD:
|
||||
return shm_rbptr_fd(client, &pcm->appl);
|
||||
default:
|
||||
ERROR("Bogus cmd: %x", ctrl->cmd);
|
||||
ctrl->result = -ENOSYS;
|
||||
|
|
|
|||
|
|
@ -47,12 +47,21 @@ typedef enum _snd_transport_type {
|
|||
#define SND_PCM_IOCTL_ASYNC _IO ('A', 0xf6)
|
||||
#define SND_PCM_IOCTL_CLOSE _IO ('A', 0xf7)
|
||||
#define SND_PCM_IOCTL_POLL_DESCRIPTOR _IO ('A', 0xf8)
|
||||
#define SND_PCM_IOCTL_HW_PTR_FD _IO ('A', 0xf9)
|
||||
#define SND_PCM_IOCTL_APPL_PTR_FD _IO ('A', 0xfa)
|
||||
|
||||
typedef struct {
|
||||
snd_pcm_uframes_t ptr;
|
||||
int use_mmap;
|
||||
off_t offset; /* for mmap */
|
||||
int changed;
|
||||
} snd_pcm_shm_rbptr_t;
|
||||
|
||||
typedef struct {
|
||||
long result;
|
||||
int cmd;
|
||||
snd_pcm_uframes_t hw_ptr;
|
||||
snd_pcm_uframes_t appl_ptr;
|
||||
snd_pcm_shm_rbptr_t hw;
|
||||
snd_pcm_shm_rbptr_t appl;
|
||||
union {
|
||||
struct {
|
||||
int sig;
|
||||
|
|
@ -80,6 +89,11 @@ typedef struct {
|
|||
snd_pcm_uframes_t offset;
|
||||
snd_pcm_uframes_t frames;
|
||||
} mmap_commit;
|
||||
struct {
|
||||
char use_mmap;
|
||||
int shmid;
|
||||
off_t offset;
|
||||
} rbptr;
|
||||
} u;
|
||||
char data[0];
|
||||
} snd_pcm_shm_ctrl_t;
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ typedef enum _snd_set_mode {
|
|||
|
||||
size_t page_align(size_t size);
|
||||
size_t page_size(void);
|
||||
size_t page_ptr(size_t object_offset, size_t object_size, size_t *offset, size_t *mmap_offset);
|
||||
|
||||
int safe_strtol(const char *str, long *val);
|
||||
|
||||
|
|
|
|||
|
|
@ -827,8 +827,8 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int
|
|||
|
||||
snd_pcm_sframes_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes);
|
||||
ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, snd_pcm_sframes_t frames);
|
||||
int snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes);
|
||||
ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, int samples);
|
||||
long snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes);
|
||||
ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, long samples);
|
||||
|
||||
int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_channel, snd_pcm_uframes_t dst_offset,
|
||||
unsigned int samples, snd_pcm_format_t format);
|
||||
|
|
|
|||
117
src/pcm/pcm.c
117
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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 = ©->plug.hw_ptr;
|
||||
pcm->appl_ptr = ©->plug.appl_ptr;
|
||||
snd_pcm_set_hw_ptr(pcm, ©->plug.hw_ptr, -1, 0);
|
||||
snd_pcm_set_appl_ptr(pcm, ©->plug.appl_ptr, -1, 0);
|
||||
*pcmp = pcm;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,12 +93,67 @@ int receive_fd(int sock, void *data, size_t len, int *fd)
|
|||
}
|
||||
#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 = receive_fd(shm->socket, buf, 1, fd);
|
||||
if (err != 1)
|
||||
return -EBADFD;
|
||||
if (ctrl->cmd) {
|
||||
SNDERR("Server has not done the cmd");
|
||||
return -EBADFD;
|
||||
}
|
||||
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;
|
||||
|
|
@ -109,7 +164,20 @@ static long snd_pcm_shm_action(snd_pcm_t *pcm)
|
|||
SNDERR("Server has not done the cmd");
|
||||
return -EBADFD;
|
||||
}
|
||||
return ctrl->result;
|
||||
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)
|
||||
|
|
@ -118,6 +186,9 @@ static long snd_pcm_shm_action_fd(snd_pcm_t *pcm, int *fd)
|
|||
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;
|
||||
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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue