mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Misc fixes and race condition cleaning
This commit is contained in:
parent
633815a591
commit
d5c49aaa8e
6 changed files with 295 additions and 283 deletions
|
|
@ -467,17 +467,7 @@ int pcm_shm_cmd(client_t *client)
|
||||||
}
|
}
|
||||||
case SND_PCM_IOCTL_MUNMAP:
|
case SND_PCM_IOCTL_MUNMAP:
|
||||||
{
|
{
|
||||||
size_t k;
|
|
||||||
ctrl->result = snd_pcm_munmap(pcm);
|
ctrl->result = snd_pcm_munmap(pcm);
|
||||||
if (ctrl->result < 0)
|
|
||||||
break;
|
|
||||||
for (k = 0; k < pcm->mmap_info_count; ++k) {
|
|
||||||
snd_pcm_mmap_info_t *i = &pcm->mmap_info[k];
|
|
||||||
if (i->type == SND_PCM_MMAP_USER) {
|
|
||||||
int err = shmdt(i->addr);
|
|
||||||
assert(err >= 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SND_PCM_IOCTL_MMAP_FORWARD:
|
case SND_PCM_IOCTL_MMAP_FORWARD:
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,12 @@ int snd_pcm_close(snd_pcm_t *pcm)
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int err;
|
int err;
|
||||||
assert(pcm);
|
assert(pcm);
|
||||||
|
if (pcm->valid_setup) {
|
||||||
|
if (pcm->mode & SND_PCM_NONBLOCK)
|
||||||
|
snd_pcm_drop(pcm);
|
||||||
|
else
|
||||||
|
snd_pcm_drain(pcm);
|
||||||
|
}
|
||||||
if (pcm->mmap_info) {
|
if (pcm->mmap_info) {
|
||||||
if ((err = snd_pcm_munmap(pcm)) < 0)
|
if ((err = snd_pcm_munmap(pcm)) < 0)
|
||||||
ret = err;
|
ret = err;
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,7 @@ static int snd_pcm_hw_drain(snd_pcm_t *pcm)
|
||||||
snd_pcm_hw_t *hw = pcm->private;
|
snd_pcm_hw_t *hw = pcm->private;
|
||||||
int fd = hw->fd;
|
int fd = hw->fd;
|
||||||
if (ioctl(fd, SND_PCM_IOCTL_DRAIN) < 0) {
|
if (ioctl(fd, SND_PCM_IOCTL_DRAIN) < 0) {
|
||||||
// SYSERR("SND_PCM_IOCTL_DRAIN failed");
|
SYSERR("SND_PCM_IOCTL_DRAIN failed");
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -620,8 +620,10 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **pcmp, int card, int device, int subdev
|
||||||
fmode |= O_NONBLOCK;
|
fmode |= O_NONBLOCK;
|
||||||
if (mode & SND_PCM_ASYNC)
|
if (mode & SND_PCM_ASYNC)
|
||||||
fmode |= O_ASYNC;
|
fmode |= O_ASYNC;
|
||||||
if ((fd = open(filename, fmode)) < 0)
|
if ((fd = open(filename, fmode)) < 0) {
|
||||||
|
SYSERR("open %s failed", filename);
|
||||||
return -errno;
|
return -errno;
|
||||||
|
}
|
||||||
if (ioctl(fd, SND_PCM_IOCTL_PVERSION, &ver) < 0) {
|
if (ioctl(fd, SND_PCM_IOCTL_PVERSION, &ver) < 0) {
|
||||||
SYSERR("SND_PCM_IOCTL_PVERSION failed");
|
SYSERR("SND_PCM_IOCTL_PVERSION failed");
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
|
|
|
||||||
|
|
@ -315,8 +315,10 @@ static int snd_pcm_rate_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
|
||||||
|
|
||||||
memset(&slave_info, 0, sizeof(slave_info));
|
memset(&slave_info, 0, sizeof(slave_info));
|
||||||
slave_info.req = *params;
|
slave_info.req = *params;
|
||||||
if (rate->req_sformat >= 0)
|
if (rate->req_sformat >= 0) {
|
||||||
slave_info.req.format.sfmt = rate->req_sformat;
|
slave_info.req.format.sfmt = rate->req_sformat;
|
||||||
|
slave_params.format.sfmt = rate->req_sformat;
|
||||||
|
}
|
||||||
slave_info.req.format.rate = rate->req_srate;
|
slave_info.req.format.rate = rate->req_srate;
|
||||||
slave_info.req_mask = ~0;
|
slave_info.req_mask = ~0;
|
||||||
err = snd_pcm_params_info(slave, &slave_info);
|
err = snd_pcm_params_info(slave, &slave_info);
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,6 @@ typedef struct {
|
||||||
int async_sig;
|
int async_sig;
|
||||||
pid_t async_pid;
|
pid_t async_pid;
|
||||||
struct timeval trigger_time;
|
struct timeval trigger_time;
|
||||||
size_t draining_silence;
|
|
||||||
int state;
|
int state;
|
||||||
size_t hw_ptr;
|
size_t hw_ptr;
|
||||||
size_t appl_ptr;
|
size_t appl_ptr;
|
||||||
|
|
@ -73,31 +72,38 @@ typedef struct {
|
||||||
} snd_pcm_share_t;
|
} snd_pcm_share_t;
|
||||||
|
|
||||||
|
|
||||||
static void snd_pcm_share_interrupt(snd_pcm_share_slave_t *slave)
|
static void _snd_pcm_share_stop(snd_pcm_t *pcm, int state);
|
||||||
|
|
||||||
|
|
||||||
|
static void _snd_pcm_update_poll(snd_pcm_t *pcm)
|
||||||
{
|
{
|
||||||
struct list_head *i;
|
snd_pcm_share_t *share = pcm->private;
|
||||||
pthread_mutex_lock(&slave->mutex);
|
snd_pcm_share_slave_t *slave = share->slave;
|
||||||
/* Update poll status */
|
size_t avail;
|
||||||
for (i = slave->clients.next; i != &slave->clients; i = i->next) {
|
|
||||||
snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
|
|
||||||
snd_pcm_t *pcm = share->pcm;
|
|
||||||
int ready;
|
int ready;
|
||||||
switch (share->state) {
|
switch (share->state) {
|
||||||
case SND_PCM_STATE_DRAINING:
|
case SND_PCM_STATE_DRAINING:
|
||||||
if (pcm->stream == SND_PCM_STREAM_CAPTURE)
|
if (pcm->stream == SND_PCM_STREAM_CAPTURE)
|
||||||
ready = 1;
|
ready = 1;
|
||||||
else {
|
else {
|
||||||
if (pcm->mode & SND_PCM_ASYNC)
|
|
||||||
kill(share->async_pid, share->async_sig);
|
|
||||||
share->hw_ptr = *slave->pcm->hw_ptr;
|
share->hw_ptr = *slave->pcm->hw_ptr;
|
||||||
|
avail = snd_pcm_mmap_avail(pcm);
|
||||||
|
if (avail >= pcm->setup.buffer_size) {
|
||||||
|
_snd_pcm_share_stop(pcm, SND_PCM_STATE_SETUP);
|
||||||
|
ready = 1;
|
||||||
|
} else
|
||||||
ready = 0;
|
ready = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SND_PCM_STATE_RUNNING:
|
case SND_PCM_STATE_RUNNING:
|
||||||
if (pcm->mode & SND_PCM_ASYNC)
|
|
||||||
kill(share->async_pid, share->async_sig);
|
|
||||||
share->hw_ptr = *slave->pcm->hw_ptr;
|
share->hw_ptr = *slave->pcm->hw_ptr;
|
||||||
ready = (snd_pcm_mmap_avail(pcm) >= pcm->setup.avail_min);
|
avail = snd_pcm_mmap_avail(pcm);
|
||||||
|
if (avail >= pcm->setup.buffer_size &&
|
||||||
|
pcm->setup.xrun_mode != SND_PCM_XRUN_NONE) {
|
||||||
|
_snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
|
||||||
|
ready = 1;
|
||||||
|
} else
|
||||||
|
ready = (avail >= pcm->setup.avail_min);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ready = 1;
|
ready = 1;
|
||||||
|
|
@ -118,6 +124,31 @@ static void snd_pcm_share_interrupt(snd_pcm_share_slave_t *slave)
|
||||||
share->ready = ready;
|
share->ready = ready;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void snd_pcm_share_interrupt(snd_pcm_share_slave_t *slave)
|
||||||
|
{
|
||||||
|
struct list_head *i;
|
||||||
|
pthread_mutex_lock(&slave->mutex);
|
||||||
|
snd_pcm_avail_update(slave->pcm);
|
||||||
|
/* Update poll status */
|
||||||
|
for (i = slave->clients.next; i != &slave->clients; i = i->next) {
|
||||||
|
snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
|
||||||
|
snd_pcm_t *pcm = share->pcm;
|
||||||
|
switch (share->state) {
|
||||||
|
case SND_PCM_STATE_DRAINING:
|
||||||
|
if (pcm->stream == SND_PCM_STREAM_CAPTURE)
|
||||||
|
break;
|
||||||
|
/* Fall through */
|
||||||
|
case SND_PCM_STATE_RUNNING:
|
||||||
|
if (pcm->mode & SND_PCM_ASYNC)
|
||||||
|
kill(share->async_pid, share->async_sig);
|
||||||
|
_snd_pcm_update_poll(pcm);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
pthread_mutex_unlock(&slave->mutex);
|
pthread_mutex_unlock(&slave->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,30 +179,7 @@ void *snd_pcm_share_slave_thread(void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Warning: take the mutex before to call this */
|
/* Warning: take the mutex before to call this */
|
||||||
static void snd_pcm_share_stop(snd_pcm_t *pcm, int state)
|
static void _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
|
||||||
{
|
|
||||||
snd_pcm_share_t *share = pcm->private;
|
|
||||||
snd_pcm_share_slave_t *slave = share->slave;
|
|
||||||
share->state = state;
|
|
||||||
gettimeofday(&share->trigger_time, 0);
|
|
||||||
slave->prepared_count--;
|
|
||||||
slave->running_count--;
|
|
||||||
if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
|
|
||||||
snd_pcm_avail_update(slave->pcm);
|
|
||||||
share->hw_ptr = *slave->pcm->hw_ptr;
|
|
||||||
snd_pcm_areas_copy(pcm->running_areas, 0,
|
|
||||||
pcm->stopped_areas, 0,
|
|
||||||
pcm->setup.format.channels, pcm->setup.buffer_size,
|
|
||||||
pcm->setup.format.sfmt);
|
|
||||||
}
|
|
||||||
if (slave->running_count == 0) {
|
|
||||||
int err = snd_pcm_drop(slave->pcm);
|
|
||||||
assert(err >= 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Warning: take the mutex before to call this */
|
|
||||||
static void snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
|
|
||||||
{
|
{
|
||||||
struct list_head *i;
|
struct list_head *i;
|
||||||
size_t buffer_size, boundary;
|
size_t buffer_size, boundary;
|
||||||
|
|
@ -180,10 +188,14 @@ static void snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
|
||||||
size_t min_frames, max_frames;
|
size_t min_frames, max_frames;
|
||||||
ssize_t avail;
|
ssize_t avail;
|
||||||
int err;
|
int err;
|
||||||
|
#if 0
|
||||||
avail = snd_pcm_avail_update(slave->pcm);
|
avail = snd_pcm_avail_update(slave->pcm);
|
||||||
if (avail == 0)
|
if (avail <= 0)
|
||||||
return;
|
return;
|
||||||
assert(avail > 0);
|
assert(avail > 0);
|
||||||
|
#else
|
||||||
|
avail = snd_pcm_mmap_avail(slave->pcm);
|
||||||
|
#endif
|
||||||
boundary = slave->pcm->setup.boundary;
|
boundary = slave->pcm->setup.boundary;
|
||||||
buffer_size = slave->pcm->setup.buffer_size;
|
buffer_size = slave->pcm->setup.buffer_size;
|
||||||
min_frames = buffer_size;
|
min_frames = buffer_size;
|
||||||
|
|
@ -194,35 +206,13 @@ static void snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
|
||||||
snd_pcm_t *pcm = share->pcm;
|
snd_pcm_t *pcm = share->pcm;
|
||||||
switch (share->state) {
|
switch (share->state) {
|
||||||
case SND_PCM_STATE_RUNNING:
|
case SND_PCM_STATE_RUNNING:
|
||||||
share->hw_ptr = *slave->pcm->hw_ptr;
|
// share->hw_ptr = *slave->pcm->hw_ptr;
|
||||||
break;
|
break;
|
||||||
case SND_PCM_STATE_DRAINING:
|
case SND_PCM_STATE_DRAINING:
|
||||||
{
|
{
|
||||||
size_t a, offset;
|
|
||||||
if (pcm->stream != SND_PCM_STREAM_PLAYBACK)
|
if (pcm->stream != SND_PCM_STREAM_PLAYBACK)
|
||||||
continue;
|
continue;
|
||||||
share->hw_ptr = *slave->pcm->hw_ptr;
|
// share->hw_ptr = *slave->pcm->hw_ptr;
|
||||||
a = snd_pcm_mmap_avail(pcm);
|
|
||||||
frames = a - share->draining_silence;
|
|
||||||
offset = snd_pcm_mmap_offset(pcm);
|
|
||||||
offset += share->draining_silence;
|
|
||||||
if (offset >= buffer_size)
|
|
||||||
offset -= buffer_size;
|
|
||||||
while (frames > 0) {
|
|
||||||
size_t f = buffer_size - offset;
|
|
||||||
if (f > (size_t) frames)
|
|
||||||
f = frames;
|
|
||||||
snd_pcm_areas_silence(pcm->running_areas, offset,
|
|
||||||
pcm->setup.format.channels,
|
|
||||||
f, pcm->setup.format.sfmt);
|
|
||||||
offset += f;
|
|
||||||
if (offset == buffer_size)
|
|
||||||
offset = 0;
|
|
||||||
frames -= f;
|
|
||||||
}
|
|
||||||
share->draining_silence = a;
|
|
||||||
if (a == buffer_size)
|
|
||||||
snd_pcm_share_stop(pcm, SND_PCM_STATE_SETUP);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
@ -234,9 +224,6 @@ static void snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
|
||||||
else if (frames < -(ssize_t)pcm->setup.buffer_size)
|
else if (frames < -(ssize_t)pcm->setup.buffer_size)
|
||||||
frames += pcm->setup.boundary;
|
frames += pcm->setup.boundary;
|
||||||
if (frames < 0) {
|
if (frames < 0) {
|
||||||
if (snd_pcm_mmap_hw_avail(pcm) <= 0 &&
|
|
||||||
pcm->setup.xrun_mode != SND_PCM_XRUN_NONE)
|
|
||||||
snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ((size_t)frames < min_frames)
|
if ((size_t)frames < min_frames)
|
||||||
|
|
@ -265,43 +252,6 @@ static void snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_pcm_share_close(snd_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
snd_pcm_share_t *share = pcm->private;
|
|
||||||
snd_pcm_share_slave_t *slave = share->slave;
|
|
||||||
int err = 0;
|
|
||||||
if (share->state == SND_PCM_STATE_RUNNING) {
|
|
||||||
if (pcm->mode & SND_PCM_NONBLOCK)
|
|
||||||
snd_pcm_drop(pcm);
|
|
||||||
else
|
|
||||||
snd_pcm_drain(pcm);
|
|
||||||
}
|
|
||||||
pthread_mutex_lock(&slave->mutex);
|
|
||||||
if (pcm->valid_setup)
|
|
||||||
slave->setup_count--;
|
|
||||||
slave->open_count--;
|
|
||||||
if (slave->open_count == 0) {
|
|
||||||
err = pthread_cancel(slave->thread);
|
|
||||||
assert(err == 0);
|
|
||||||
err = pthread_join(slave->thread, 0);
|
|
||||||
assert(err == 0);
|
|
||||||
err = snd_pcm_close(slave->pcm);
|
|
||||||
list_del(&slave->list);
|
|
||||||
pthread_mutex_unlock(&slave->mutex);
|
|
||||||
pthread_mutex_destroy(&slave->mutex);
|
|
||||||
free(slave);
|
|
||||||
list_del(&share->list);
|
|
||||||
} else {
|
|
||||||
list_del(&share->list);
|
|
||||||
pthread_mutex_unlock(&slave->mutex);
|
|
||||||
}
|
|
||||||
close(share->client_socket);
|
|
||||||
close(share->slave_socket);
|
|
||||||
free(share->slave_channels);
|
|
||||||
free(share);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int snd_pcm_share_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
|
static int snd_pcm_share_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -345,6 +295,7 @@ static int snd_pcm_share_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info
|
||||||
err = snd_pcm_params_info(slave->pcm, info);
|
err = snd_pcm_params_info(slave->pcm, info);
|
||||||
info->req.format.channels = channels;
|
info->req.format.channels = channels;
|
||||||
info->req_mask = req_mask;
|
info->req_mask = req_mask;
|
||||||
|
pthread_mutex_lock(&slave->mutex);
|
||||||
if (slave->setup_count > 1 ||
|
if (slave->setup_count > 1 ||
|
||||||
(slave->setup_count == 1 && !pcm->valid_setup)) {
|
(slave->setup_count == 1 && !pcm->valid_setup)) {
|
||||||
snd_pcm_setup_t *s = &slave->pcm->setup;
|
snd_pcm_setup_t *s = &slave->pcm->setup;
|
||||||
|
|
@ -352,7 +303,8 @@ static int snd_pcm_share_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info
|
||||||
info->req.format.sfmt != s->format.sfmt) {
|
info->req.format.sfmt != s->format.sfmt) {
|
||||||
info->req.fail_mask |= SND_PCM_PARAMS_SFMT;
|
info->req.fail_mask |= SND_PCM_PARAMS_SFMT;
|
||||||
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
|
||||||
return -EINVAL;
|
err = -EINVAL;
|
||||||
|
goto _end;
|
||||||
}
|
}
|
||||||
info->formats = 1 << s->format.sfmt;
|
info->formats = 1 << s->format.sfmt;
|
||||||
info->rates = SND_PCM_RATE_CONTINUOUS;
|
info->rates = SND_PCM_RATE_CONTINUOUS;
|
||||||
|
|
@ -369,6 +321,8 @@ static int snd_pcm_share_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info
|
||||||
info->flags &= ~SND_PCM_INFO_INTERLEAVED;
|
info->flags &= ~SND_PCM_INFO_INTERLEAVED;
|
||||||
info->flags |= SND_PCM_INFO_COMPLEX;
|
info->flags |= SND_PCM_INFO_COMPLEX;
|
||||||
}
|
}
|
||||||
|
_end:
|
||||||
|
pthread_mutex_unlock(&slave->mutex);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -378,41 +332,44 @@ static int snd_pcm_share_mmap(snd_pcm_t *pcm)
|
||||||
snd_pcm_share_slave_t *slave = share->slave;
|
snd_pcm_share_slave_t *slave = share->slave;
|
||||||
snd_pcm_mmap_info_t *i;
|
snd_pcm_mmap_info_t *i;
|
||||||
size_t count;
|
size_t count;
|
||||||
int err;
|
int err = 0;
|
||||||
pthread_mutex_lock(&slave->mutex);
|
pthread_mutex_lock(&slave->mutex);
|
||||||
if (slave->mmap_count == 0) {
|
if (slave->mmap_count == 0) {
|
||||||
err = snd_pcm_mmap(slave->pcm);
|
err = snd_pcm_mmap(slave->pcm);
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
pthread_mutex_unlock(&slave->mutex);
|
goto _end;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK)
|
||||||
snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->setup.format.channels, slave->pcm->setup.buffer_size, slave->pcm->setup.format.sfmt);
|
snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->setup.format.channels, slave->pcm->setup.buffer_size, slave->pcm->setup.format.sfmt);
|
||||||
slave->mmap_count++;
|
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&slave->mutex);
|
slave->mmap_count++;
|
||||||
count = slave->pcm->mmap_info_count;
|
count = slave->pcm->mmap_info_count;
|
||||||
i = malloc((count + 1) * sizeof(*i));
|
i = malloc((count + 1) * sizeof(*i));
|
||||||
if (!i)
|
if (!i) {
|
||||||
return -ENOMEM;
|
err = -ENOMEM;
|
||||||
|
goto _end;
|
||||||
|
}
|
||||||
i->type = SND_PCM_MMAP_USER;
|
i->type = SND_PCM_MMAP_USER;
|
||||||
i->size = snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size);
|
i->size = snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size);
|
||||||
i->u.user.shmid = shmget(IPC_PRIVATE, i->size, 0666);
|
i->u.user.shmid = shmget(IPC_PRIVATE, i->size, 0666);
|
||||||
if (i->u.user.shmid < 0) {
|
if (i->u.user.shmid < 0) {
|
||||||
SYSERR("shmget failed");
|
SYSERR("shmget failed");
|
||||||
free(i);
|
free(i);
|
||||||
return -errno;
|
err = -errno;
|
||||||
|
goto _end;
|
||||||
}
|
}
|
||||||
i->addr = shmat(i->u.user.shmid, 0, 0);
|
i->addr = shmat(i->u.user.shmid, 0, 0);
|
||||||
if (i->addr == (void*) -1) {
|
if (i->addr == (void*) -1) {
|
||||||
SYSERR("shmat failed");
|
SYSERR("shmat failed");
|
||||||
free(i);
|
free(i);
|
||||||
return -errno;
|
err = -errno;
|
||||||
|
goto _end;
|
||||||
}
|
}
|
||||||
share->stopped_data = i->addr;
|
share->stopped_data = i->addr;
|
||||||
memcpy(i + 1, slave->pcm->mmap_info, count * sizeof(*pcm->mmap_info));
|
memcpy(i + 1, slave->pcm->mmap_info, count * sizeof(*pcm->mmap_info));
|
||||||
pcm->mmap_info_count = count + 1;
|
pcm->mmap_info_count = count + 1;
|
||||||
pcm->mmap_info = i;
|
pcm->mmap_info = i;
|
||||||
|
_end:
|
||||||
|
pthread_mutex_unlock(&slave->mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -420,30 +377,32 @@ static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
snd_pcm_share_t *share = pcm->private;
|
snd_pcm_share_t *share = pcm->private;
|
||||||
snd_pcm_share_slave_t *slave = share->slave;
|
snd_pcm_share_slave_t *slave = share->slave;
|
||||||
int err;
|
snd_pcm_mmap_info_t *i = pcm->mmap_info;
|
||||||
|
int err = 0;
|
||||||
pthread_mutex_lock(&slave->mutex);
|
pthread_mutex_lock(&slave->mutex);
|
||||||
slave->mmap_count--;
|
slave->mmap_count--;
|
||||||
if (slave->mmap_count == 0) {
|
if (slave->mmap_count == 0) {
|
||||||
err = snd_pcm_munmap(slave->pcm);
|
err = snd_pcm_munmap(slave->pcm);
|
||||||
if (err < 0) {
|
if (err < 0)
|
||||||
|
goto _end;
|
||||||
|
}
|
||||||
|
if (shmdt(i->addr) < 0) {
|
||||||
|
SYSERR("shmdt failed");
|
||||||
|
err = -errno;
|
||||||
|
goto _end;
|
||||||
|
}
|
||||||
|
if (shmctl(i->u.user.shmid, IPC_RMID, 0) < 0) {
|
||||||
|
SYSERR("shmctl IPC_RMID failed");
|
||||||
|
err =-errno;
|
||||||
|
goto _end;
|
||||||
|
}
|
||||||
|
free(i);
|
||||||
|
pcm->mmap_info_count = 0;
|
||||||
|
pcm->mmap_info = 0;
|
||||||
|
_end:
|
||||||
pthread_mutex_unlock(&slave->mutex);
|
pthread_mutex_unlock(&slave->mutex);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&slave->mutex);
|
|
||||||
if (shmdt(pcm->mmap_info->addr) < 0) {
|
|
||||||
SYSERR("shmdt failed");
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
if (shmctl(pcm->mmap_info->u.user.shmid, IPC_RMID, 0) < 0) {
|
|
||||||
SYSERR("shmctl IPC_RMID failed");
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
pcm->mmap_info_count = 0;
|
|
||||||
free(pcm->mmap_info);
|
|
||||||
pcm->mmap_info = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
|
static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
|
||||||
{
|
{
|
||||||
|
|
@ -464,6 +423,7 @@ static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
|
||||||
(slave->setup_count == 1 && !pcm->valid_setup)) {
|
(slave->setup_count == 1 && !pcm->valid_setup)) {
|
||||||
snd_pcm_setup_t *s = &slave->pcm->setup;
|
snd_pcm_setup_t *s = &slave->pcm->setup;
|
||||||
if (params->format.sfmt != s->format.sfmt) {
|
if (params->format.sfmt != s->format.sfmt) {
|
||||||
|
printf("%d %d\n", params->format.sfmt, s->format.sfmt);
|
||||||
ERR("slave is already running with different format");
|
ERR("slave is already running with different format");
|
||||||
params->fail_mask |= SND_PCM_PARAMS_SFMT;
|
params->fail_mask |= SND_PCM_PARAMS_SFMT;
|
||||||
}
|
}
|
||||||
|
|
@ -544,17 +504,15 @@ static int snd_pcm_share_state(snd_pcm_t *pcm)
|
||||||
return share->state;
|
return share->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_pcm_share_delay(snd_pcm_t *pcm, ssize_t *delayp)
|
static int _snd_pcm_share_delay(snd_pcm_t *pcm, ssize_t *delayp)
|
||||||
{
|
{
|
||||||
snd_pcm_share_t *share = pcm->private;
|
snd_pcm_share_t *share = pcm->private;
|
||||||
snd_pcm_share_slave_t *slave = share->slave;
|
snd_pcm_share_slave_t *slave = share->slave;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
ssize_t sd;
|
ssize_t sd;
|
||||||
pthread_mutex_lock(&slave->mutex);
|
|
||||||
switch (share->state) {
|
switch (share->state) {
|
||||||
case SND_PCM_STATE_XRUN:
|
case SND_PCM_STATE_XRUN:
|
||||||
err = -EPIPE;
|
return -EPIPE;
|
||||||
goto _end;
|
|
||||||
case SND_PCM_STATE_RUNNING:
|
case SND_PCM_STATE_RUNNING:
|
||||||
break;
|
break;
|
||||||
case SND_PCM_STATE_DRAINING:
|
case SND_PCM_STATE_DRAINING:
|
||||||
|
|
@ -562,18 +520,26 @@ static int snd_pcm_share_delay(snd_pcm_t *pcm, ssize_t *delayp)
|
||||||
break;
|
break;
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
default:
|
default:
|
||||||
err = -EBADFD;
|
return -EBADFD;
|
||||||
goto _end;
|
|
||||||
}
|
}
|
||||||
err = snd_pcm_delay(slave->pcm, &sd);
|
err = snd_pcm_delay(slave->pcm, &sd);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto _end;
|
return err;
|
||||||
*delayp = sd + snd_pcm_mmap_delay(pcm);
|
*delayp = sd + snd_pcm_mmap_delay(pcm);
|
||||||
_end:
|
|
||||||
pthread_mutex_unlock(&slave->mutex);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int snd_pcm_share_delay(snd_pcm_t *pcm, ssize_t *delayp)
|
||||||
|
{
|
||||||
|
snd_pcm_share_t *share = pcm->private;
|
||||||
|
snd_pcm_share_slave_t *slave = share->slave;
|
||||||
|
int err;
|
||||||
|
pthread_mutex_lock(&slave->mutex);
|
||||||
|
err = _snd_pcm_share_delay(pcm, delayp);
|
||||||
|
pthread_mutex_unlock(&slave->mutex);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
|
static ssize_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
|
||||||
{
|
{
|
||||||
snd_pcm_share_t *share = pcm->private;
|
snd_pcm_share_t *share = pcm->private;
|
||||||
|
|
@ -583,26 +549,16 @@ static ssize_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
|
||||||
ret = snd_pcm_avail_update(slave->pcm);
|
ret = snd_pcm_avail_update(slave->pcm);
|
||||||
if (share->state == SND_PCM_STATE_RUNNING)
|
if (share->state == SND_PCM_STATE_RUNNING)
|
||||||
share->hw_ptr = *slave->pcm->hw_ptr;
|
share->hw_ptr = *slave->pcm->hw_ptr;
|
||||||
if (ret == -EPIPE) {
|
|
||||||
struct list_head *i;
|
|
||||||
for (i = slave->clients.next; i != &slave->clients; i = i->next) {
|
|
||||||
snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
|
|
||||||
snd_pcm_t *pcm = share->pcm;
|
|
||||||
if (share->state == SND_PCM_STATE_RUNNING &&
|
|
||||||
pcm->setup.xrun_mode != SND_PCM_XRUN_NONE)
|
|
||||||
snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&slave->mutex);
|
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
ret = snd_pcm_mmap_avail(pcm);
|
ret = snd_pcm_mmap_avail(pcm);
|
||||||
if ((size_t)ret > pcm->setup.buffer_size) {
|
if ((size_t)ret > pcm->setup.buffer_size) {
|
||||||
if (share->state == SND_PCM_STATE_RUNNING &&
|
if (share->state == SND_PCM_STATE_RUNNING &&
|
||||||
pcm->setup.xrun_mode != SND_PCM_XRUN_NONE)
|
pcm->setup.xrun_mode != SND_PCM_XRUN_NONE)
|
||||||
snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
|
_snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
|
||||||
return -EPIPE;
|
return -EPIPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pthread_mutex_unlock(&slave->mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -629,7 +585,8 @@ static ssize_t _snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size)
|
||||||
}
|
}
|
||||||
snd_pcm_mmap_appl_forward(pcm, size);
|
snd_pcm_mmap_appl_forward(pcm, size);
|
||||||
if (share->state == SND_PCM_STATE_RUNNING)
|
if (share->state == SND_PCM_STATE_RUNNING)
|
||||||
snd_pcm_share_slave_forward(share->slave);
|
_snd_pcm_share_slave_forward(share->slave);
|
||||||
|
_snd_pcm_update_poll(pcm);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -718,90 +675,6 @@ static int snd_pcm_share_start(snd_pcm_t *pcm)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_pcm_share_drop(snd_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
snd_pcm_share_t *share = pcm->private;
|
|
||||||
snd_pcm_share_slave_t *slave = share->slave;
|
|
||||||
int err = 0;
|
|
||||||
pthread_mutex_lock(&slave->mutex);
|
|
||||||
switch (share->state) {
|
|
||||||
case SND_PCM_STATE_OPEN:
|
|
||||||
err = -EBADFD;
|
|
||||||
goto _end;
|
|
||||||
case SND_PCM_STATE_SETUP:
|
|
||||||
goto _end;
|
|
||||||
case SND_PCM_STATE_DRAINING:
|
|
||||||
if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
|
|
||||||
share->state = SND_PCM_STATE_SETUP;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Fall through */
|
|
||||||
case SND_PCM_STATE_RUNNING:
|
|
||||||
snd_pcm_share_stop(pcm, SND_PCM_STATE_SETUP);
|
|
||||||
break;
|
|
||||||
case SND_PCM_STATE_PREPARED:
|
|
||||||
case SND_PCM_STATE_XRUN:
|
|
||||||
share->state = SND_PCM_STATE_SETUP;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slave->running_count > 0 &&
|
|
||||||
pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
|
||||||
ssize_t delay;
|
|
||||||
err = snd_pcm_delay(pcm, &delay);
|
|
||||||
if (err < 0)
|
|
||||||
goto _end;
|
|
||||||
if (delay > 0) {
|
|
||||||
err = snd_pcm_rewind(pcm, delay);
|
|
||||||
if (err < 0)
|
|
||||||
goto _end;
|
|
||||||
}
|
|
||||||
snd_pcm_areas_silence(pcm->running_areas, 0, pcm->setup.format.channels,
|
|
||||||
pcm->setup.buffer_size, pcm->setup.format.sfmt);
|
|
||||||
snd_pcm_mmap_forward(pcm, pcm->setup.buffer_size);
|
|
||||||
}
|
|
||||||
share->appl_ptr = share->hw_ptr = 0;
|
|
||||||
_end:
|
|
||||||
pthread_mutex_unlock(&slave->mutex);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int snd_pcm_share_drain(snd_pcm_t *pcm)
|
|
||||||
{
|
|
||||||
snd_pcm_share_t *share = pcm->private;
|
|
||||||
snd_pcm_share_slave_t *slave = share->slave;
|
|
||||||
int err = 0;
|
|
||||||
pthread_mutex_lock(&slave->mutex);
|
|
||||||
switch (share->state) {
|
|
||||||
case SND_PCM_STATE_OPEN:
|
|
||||||
err = -EBADFD;
|
|
||||||
goto _end;
|
|
||||||
case SND_PCM_STATE_PREPARED:
|
|
||||||
share->state = SND_PCM_STATE_SETUP;
|
|
||||||
break;
|
|
||||||
case SND_PCM_STATE_SETUP:
|
|
||||||
case SND_PCM_STATE_DRAINING:
|
|
||||||
goto _end;
|
|
||||||
case SND_PCM_STATE_XRUN:
|
|
||||||
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
|
||||||
share->state = SND_PCM_STATE_SETUP;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Fall through */
|
|
||||||
case SND_PCM_STATE_RUNNING:
|
|
||||||
if (snd_pcm_mmap_avail(pcm) <= 0) {
|
|
||||||
share->state = SND_PCM_STATE_SETUP;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
share->draining_silence = 0;
|
|
||||||
share->state = SND_PCM_STATE_DRAINING;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_end:
|
|
||||||
pthread_mutex_unlock(&slave->mutex);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int snd_pcm_share_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
|
static int snd_pcm_share_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
|
|
@ -865,11 +738,10 @@ static int snd_pcm_share_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
|
static ssize_t _snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
|
||||||
{
|
{
|
||||||
snd_pcm_share_t *share = pcm->private;
|
snd_pcm_share_t *share = pcm->private;
|
||||||
snd_pcm_share_slave_t *slave = share->slave;
|
snd_pcm_share_slave_t *slave = share->slave;
|
||||||
int ret = -EBADFD;
|
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
switch (share->state) {
|
switch (share->state) {
|
||||||
case SND_PCM_STATE_RUNNING:
|
case SND_PCM_STATE_RUNNING:
|
||||||
|
|
@ -885,7 +757,7 @@ static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
|
||||||
case SND_PCM_STATE_XRUN:
|
case SND_PCM_STATE_XRUN:
|
||||||
return -EPIPE;
|
return -EPIPE;
|
||||||
default:
|
default:
|
||||||
goto _err;
|
return -EBADFD;
|
||||||
}
|
}
|
||||||
n = snd_pcm_mmap_hw_avail(pcm);
|
n = snd_pcm_mmap_hw_avail(pcm);
|
||||||
assert(n >= 0);
|
assert(n >= 0);
|
||||||
|
|
@ -896,20 +768,24 @@ static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
|
||||||
}
|
}
|
||||||
if (share->state == SND_PCM_STATE_RUNNING &&
|
if (share->state == SND_PCM_STATE_RUNNING &&
|
||||||
frames > 0) {
|
frames > 0) {
|
||||||
pthread_mutex_lock(&slave->mutex);
|
int ret = snd_pcm_rewind(slave->pcm, frames);
|
||||||
ret = snd_pcm_rewind(slave->pcm, frames);
|
if (ret < 0)
|
||||||
pthread_mutex_unlock(&slave->mutex);
|
|
||||||
if (ret < 0) {
|
|
||||||
if (n <= 0)
|
|
||||||
return ret;
|
return ret;
|
||||||
goto _end;
|
|
||||||
}
|
|
||||||
n += ret;
|
n += ret;
|
||||||
}
|
}
|
||||||
_end:
|
|
||||||
snd_pcm_mmap_appl_backward(pcm, n);
|
snd_pcm_mmap_appl_backward(pcm, n);
|
||||||
ret = n;
|
_snd_pcm_update_poll(pcm);
|
||||||
_err:
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
|
||||||
|
{
|
||||||
|
snd_pcm_share_t *share = pcm->private;
|
||||||
|
snd_pcm_share_slave_t *slave = share->slave;
|
||||||
|
ssize_t ret;
|
||||||
|
pthread_mutex_lock(&slave->mutex);
|
||||||
|
ret = _snd_pcm_share_rewind(pcm, frames);
|
||||||
|
pthread_mutex_unlock(&slave->mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -929,6 +805,148 @@ static int snd_pcm_share_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Warning: take the mutex before to call this */
|
||||||
|
static void _snd_pcm_share_stop(snd_pcm_t *pcm, int state)
|
||||||
|
{
|
||||||
|
snd_pcm_share_t *share = pcm->private;
|
||||||
|
snd_pcm_share_slave_t *slave = share->slave;
|
||||||
|
if (!pcm->mmap_info) {
|
||||||
|
/* PCM closing already begun in the main thread */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gettimeofday(&share->trigger_time, 0);
|
||||||
|
if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
|
||||||
|
snd_pcm_areas_copy(pcm->running_areas, 0,
|
||||||
|
pcm->stopped_areas, 0,
|
||||||
|
pcm->setup.format.channels, pcm->setup.buffer_size,
|
||||||
|
pcm->setup.format.sfmt);
|
||||||
|
} else if (slave->running_count > 1) {
|
||||||
|
int err;
|
||||||
|
ssize_t delay;
|
||||||
|
snd_pcm_areas_silence(pcm->running_areas, 0, pcm->setup.format.channels,
|
||||||
|
pcm->setup.buffer_size, pcm->setup.format.sfmt);
|
||||||
|
err = snd_pcm_delay(slave->pcm, &delay);
|
||||||
|
if (err >= 0 && delay > 0)
|
||||||
|
snd_pcm_rewind(slave->pcm, delay);
|
||||||
|
_snd_pcm_share_slave_forward(slave);
|
||||||
|
}
|
||||||
|
share->state = state;
|
||||||
|
slave->prepared_count--;
|
||||||
|
slave->running_count--;
|
||||||
|
if (slave->running_count == 0) {
|
||||||
|
int err = snd_pcm_drop(slave->pcm);
|
||||||
|
assert(err >= 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int snd_pcm_share_drain(snd_pcm_t *pcm)
|
||||||
|
{
|
||||||
|
snd_pcm_share_t *share = pcm->private;
|
||||||
|
snd_pcm_share_slave_t *slave = share->slave;
|
||||||
|
int err = 0;
|
||||||
|
pthread_mutex_lock(&slave->mutex);
|
||||||
|
switch (share->state) {
|
||||||
|
case SND_PCM_STATE_OPEN:
|
||||||
|
err = -EBADFD;
|
||||||
|
goto _end;
|
||||||
|
case SND_PCM_STATE_PREPARED:
|
||||||
|
share->state = SND_PCM_STATE_SETUP;
|
||||||
|
break;
|
||||||
|
case SND_PCM_STATE_SETUP:
|
||||||
|
goto _end;
|
||||||
|
case SND_PCM_STATE_DRAINING:
|
||||||
|
break;
|
||||||
|
case SND_PCM_STATE_XRUN:
|
||||||
|
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
||||||
|
share->state = SND_PCM_STATE_SETUP;
|
||||||
|
goto _end;
|
||||||
|
}
|
||||||
|
/* Fall through */
|
||||||
|
case SND_PCM_STATE_RUNNING:
|
||||||
|
if (snd_pcm_mmap_avail(pcm) <= 0) {
|
||||||
|
share->state = SND_PCM_STATE_SETUP;
|
||||||
|
goto _end;
|
||||||
|
}
|
||||||
|
share->state = SND_PCM_STATE_DRAINING;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
|
||||||
|
_snd_pcm_update_poll(pcm);
|
||||||
|
if (!(pcm->mode & SND_PCM_NONBLOCK))
|
||||||
|
snd_pcm_wait(pcm, -1);
|
||||||
|
}
|
||||||
|
_end:
|
||||||
|
pthread_mutex_unlock(&slave->mutex);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int snd_pcm_share_drop(snd_pcm_t *pcm)
|
||||||
|
{
|
||||||
|
snd_pcm_share_t *share = pcm->private;
|
||||||
|
snd_pcm_share_slave_t *slave = share->slave;
|
||||||
|
int err = 0;
|
||||||
|
pthread_mutex_lock(&slave->mutex);
|
||||||
|
switch (share->state) {
|
||||||
|
case SND_PCM_STATE_OPEN:
|
||||||
|
err = -EBADFD;
|
||||||
|
goto _end;
|
||||||
|
case SND_PCM_STATE_SETUP:
|
||||||
|
break;
|
||||||
|
case SND_PCM_STATE_DRAINING:
|
||||||
|
if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
|
||||||
|
share->state = SND_PCM_STATE_SETUP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Fall through */
|
||||||
|
case SND_PCM_STATE_RUNNING:
|
||||||
|
_snd_pcm_share_stop(pcm, SND_PCM_STATE_SETUP);
|
||||||
|
_snd_pcm_update_poll(pcm);
|
||||||
|
break;
|
||||||
|
case SND_PCM_STATE_PREPARED:
|
||||||
|
case SND_PCM_STATE_XRUN:
|
||||||
|
share->state = SND_PCM_STATE_SETUP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
share->appl_ptr = share->hw_ptr = 0;
|
||||||
|
_end:
|
||||||
|
pthread_mutex_unlock(&slave->mutex);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int snd_pcm_share_close(snd_pcm_t *pcm)
|
||||||
|
{
|
||||||
|
snd_pcm_share_t *share = pcm->private;
|
||||||
|
snd_pcm_share_slave_t *slave = share->slave;
|
||||||
|
int err = 0;
|
||||||
|
pthread_mutex_lock(&slaves_mutex);
|
||||||
|
pthread_mutex_lock(&slave->mutex);
|
||||||
|
if (pcm->valid_setup)
|
||||||
|
slave->setup_count--;
|
||||||
|
slave->open_count--;
|
||||||
|
if (slave->open_count == 0) {
|
||||||
|
err = pthread_cancel(slave->thread);
|
||||||
|
assert(err == 0);
|
||||||
|
err = pthread_join(slave->thread, 0);
|
||||||
|
assert(err == 0);
|
||||||
|
err = snd_pcm_close(slave->pcm);
|
||||||
|
pthread_mutex_unlock(&slave->mutex);
|
||||||
|
pthread_mutex_destroy(&slave->mutex);
|
||||||
|
list_del(&slave->list);
|
||||||
|
free(slave);
|
||||||
|
list_del(&share->list);
|
||||||
|
} else {
|
||||||
|
list_del(&share->list);
|
||||||
|
pthread_mutex_unlock(&slave->mutex);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&slaves_mutex);
|
||||||
|
close(share->client_socket);
|
||||||
|
close(share->slave_socket);
|
||||||
|
free(share->slave_channels);
|
||||||
|
free(share);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static void snd_pcm_share_dump(snd_pcm_t *pcm, FILE *fp)
|
static void snd_pcm_share_dump(snd_pcm_t *pcm, FILE *fp)
|
||||||
{
|
{
|
||||||
snd_pcm_share_t *share = pcm->private;
|
snd_pcm_share_t *share = pcm->private;
|
||||||
|
|
@ -1057,7 +1075,7 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, char *name, char *sname,
|
||||||
pthread_mutex_lock(&slaves_mutex);
|
pthread_mutex_lock(&slaves_mutex);
|
||||||
for (i = slaves.next; i != &slaves; i = i->next) {
|
for (i = slaves.next; i != &slaves; i = i->next) {
|
||||||
snd_pcm_share_slave_t *s = list_entry(i, snd_pcm_share_slave_t, list);
|
snd_pcm_share_slave_t *s = list_entry(i, snd_pcm_share_slave_t, list);
|
||||||
if (s->pcm->name && strcmp(s->pcm->name, sname)) {
|
if (s->pcm->name && strcmp(s->pcm->name, sname) == 0) {
|
||||||
slave = s;
|
slave = s;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1090,14 +1108,11 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, char *name, char *sname,
|
||||||
slave->channels_count = schannels_count;
|
slave->channels_count = schannels_count;
|
||||||
pthread_mutex_init(&slave->mutex, NULL);
|
pthread_mutex_init(&slave->mutex, NULL);
|
||||||
list_add_tail(&slave->list, &slaves);
|
list_add_tail(&slave->list, &slaves);
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&slaves_mutex);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&slave->mutex);
|
|
||||||
if (slave->open_count == 0) {
|
|
||||||
err = pthread_create(&slave->thread, NULL, snd_pcm_share_slave_thread, slave);
|
err = pthread_create(&slave->thread, NULL, snd_pcm_share_slave_thread, slave);
|
||||||
assert(err == 0);
|
assert(err == 0);
|
||||||
}
|
}
|
||||||
|
pthread_mutex_lock(&slave->mutex);
|
||||||
|
pthread_mutex_unlock(&slaves_mutex);
|
||||||
slave->open_count++;
|
slave->open_count++;
|
||||||
list_add_tail(&share->list, &slave->clients);
|
list_add_tail(&share->list, &slave->clients);
|
||||||
pthread_mutex_unlock(&slave->mutex);
|
pthread_mutex_unlock(&slave->mutex);
|
||||||
|
|
|
||||||
|
|
@ -468,9 +468,6 @@ static int snd_pcm_shm_close(snd_pcm_t *pcm)
|
||||||
snd_pcm_shm_t *shm = pcm->private;
|
snd_pcm_shm_t *shm = pcm->private;
|
||||||
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
|
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
|
||||||
int result;
|
int result;
|
||||||
if (!(pcm->mode & SND_PCM_NONBLOCK) &&
|
|
||||||
snd_pcm_shm_state(pcm) == SND_PCM_STATE_RUNNING)
|
|
||||||
snd_pcm_shm_drain(pcm);
|
|
||||||
ctrl->cmd = SND_PCM_IOCTL_CLOSE;
|
ctrl->cmd = SND_PCM_IOCTL_CLOSE;
|
||||||
result = snd_pcm_shm_action(pcm);
|
result = snd_pcm_shm_action(pcm);
|
||||||
shmdt((void *)ctrl);
|
shmdt((void *)ctrl);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue