Implemented snd_pcm_avail() function.

More documentation updates for snd_pcm_avail_update() and snd_pcm_delay().
Updated behaviour of read/write functions (wait when buffer is full) to
follow kernel.
This commit is contained in:
Jaroslav Kysela 2002-10-11 18:39:24 +00:00
parent 25e41cf1e8
commit e859cf2644
11 changed files with 189 additions and 69 deletions

View file

@ -359,9 +359,9 @@ network I/O etc.). If application wants to manage the ahead samples itself,
the \link ::snd_pcm_rewind() \endlink function allows to forget the last the \link ::snd_pcm_rewind() \endlink function allows to forget the last
samples in the stream. samples in the stream.
\section pcm_status Obtaining device status \section pcm_status Obtaining stream status
The device status is stored in \link ::snd_pcm_status_t \endlink structure. The stream status is stored in \link ::snd_pcm_status_t \endlink structure.
These parameters can be obtained: the current stream state - These parameters can be obtained: the current stream state -
\link ::snd_pcm_status_get_state \endlink, timestamp of trigger - \link ::snd_pcm_status_get_state \endlink, timestamp of trigger -
\link ::snd_pcm_status_get_trigger_tstamp \endlink, timestamp of last \link ::snd_pcm_status_get_trigger_tstamp \endlink, timestamp of last
@ -373,21 +373,33 @@ samples - \link ::snd_pcm_status_get_overrange \endlink. The last two
parameters - avail_max and overrange are reset to zero after the status parameters - avail_max and overrange are reset to zero after the status
call. call.
\subsection pcm_status_fast Obtaining device status fast \subsection pcm_status_fast Obtaining stream state fast and update r/w pointer
The function \link ::snd_pcm_avail_update \endlink updates the current The function \link ::snd_pcm_avail_update \endlink updates the current
available count of samples for writing (playback) or filled samples for available count of samples for writing (playback) or filled samples for
reading (capture). It is a light version of reading (capture). This call is mandatory for updating actual r/w pointer.
\link ::snd_pcm_status_get_avail \endlink, because it does not require Using standalone, it is a light method to obtain current stream position,
the user <-> kernel context switch, but the value is less accurate, because it does not require the user <-> kernel context switch, but the value
because ring buffer pointers are updated in kernel drivers only when is less accurate, because ring buffer pointers are updated in kernel drivers
an interrupt occurs. only when an interrupt occurs. If you want to get accurate stream state,
use functions \link ::snd_pcm_avail \endlink or \link ::snd_pcm_delay \endlink.
Note that both of these functions do not update the current r/w pointer
for applications, so the function \link ::snd_pcm_avail_update \endlink must
be called afterwards before any read/write begin+commit operations.
<p>
The function \link ::snd_pcm_avail \endlink returns current available space
in the ring buffer. Note that this function does not update the current r/w
pointer for applications, so the function \link ::snd_pcm_avail_update \endlink
must be called afterwards before any read/write/begin+commit operations.
<p> <p>
The function \link ::snd_pcm_delay \endlink returns the delay in samples. The function \link ::snd_pcm_delay \endlink returns the delay in samples.
For playback, it means count of samples in the ring buffer before For playback, it means count of samples in the ring buffer before
the next sample will be sent to DAC. For capture, it means count of samples the next sample will be sent to DAC. For capture, it means count of samples
in the ring buffer before the next sample will be captured from ADC. It works in the ring buffer before the next sample will be captured from ADC. It works
only when the stream is in the running or draining state. only when the stream is in the running or draining (playback only) state.
Note that this function does not update the current r/w pointer for applications,
so the function \link ::snd_pcm_avail_update \endlink must be called afterwards
before any read/write begin+commit operations.
\section pcm_action Managing the stream state \section pcm_action Managing the stream state
@ -811,6 +823,30 @@ snd_pcm_state_t snd_pcm_state(snd_pcm_t *pcm)
return pcm->fast_ops->state(pcm->fast_op_arg); return pcm->fast_ops->state(pcm->fast_op_arg);
} }
/**
* \brief Obtain available frames for a running PCM handle
* \param pcm PCM handle
* \param availp Returned available frames
* \return 0 on success otherwise a negative error code
*
* Returns available frames to be filled inside ring buffer.
* This value might be greater than buffer size when
* underrun (playback) or overrun (capture) occurs.
*
* This function returns accurate value, because it updates
* stream position from hardware.
*
* Note this function does not update the actual r/w pointer
* for applications. The function \link ::snd_pcm_avail_update \endlink
* have to be called before any read/write/begin+commit operation.
*/
int snd_pcm_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp)
{
assert(pcm);
assert(pcm->setup);
return pcm->fast_ops->avail(pcm->fast_op_arg, availp);
}
/** /**
* \brief Obtain delay for a running PCM handle * \brief Obtain delay for a running PCM handle
* \param pcm PCM handle * \param pcm PCM handle
@ -822,6 +858,10 @@ snd_pcm_state_t snd_pcm_state(snd_pcm_t *pcm)
* It's positive and less than buffer size in normal situation, * It's positive and less than buffer size in normal situation,
* negative on playback underrun and greater than buffer size on * negative on playback underrun and greater than buffer size on
* capture overrun. * capture overrun.
*
* Note this function does not update the actual r/w pointer
* for applications. The function \link ::snd_pcm_avail_update \endlink
* have to be called before any read/write/begin+commit operation.
*/ */
int snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) int snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{ {
@ -5728,6 +5768,8 @@ snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_
break; break;
case SND_PCM_STATE_XRUN: case SND_PCM_STATE_XRUN:
return -EPIPE; return -EPIPE;
case SND_PCM_STATE_SUSPENDED:
return -ESTRPIPE;
default: default:
return -EBADFD; return -EBADFD;
} }
@ -5736,19 +5778,21 @@ snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_
snd_pcm_uframes_t frames; snd_pcm_uframes_t frames;
snd_pcm_sframes_t avail; snd_pcm_sframes_t avail;
_again: _again:
if (pcm->sleep_min == 0 && state == SND_PCM_STATE_RUNNING) {
snd_pcm_sframes_t delay;
/* update hw_ptr */
err = snd_pcm_delay(pcm, &delay);
if (err < 0)
goto _end;
}
avail = snd_pcm_avail_update(pcm); avail = snd_pcm_avail_update(pcm);
if (avail < 0) { if (avail < 0) {
err = avail; err = avail;
goto _end; goto _end;
} }
if ((state == SND_PCM_STATE_PAUSED) || if (((snd_pcm_uframes_t)avail < pcm->avail_min && size > (snd_pcm_uframes_t)avail) ||
(state == SND_PCM_STATE_DRAINING)) {
if ((snd_pcm_uframes_t)avail < pcm->xfer_align) {
err = -EPIPE;
goto _end;
}
} else if (((snd_pcm_uframes_t)avail < pcm->avail_min && size > (snd_pcm_uframes_t)avail) ||
(size >= pcm->xfer_align && (snd_pcm_uframes_t)avail < pcm->xfer_align)) { (size >= pcm->xfer_align && (snd_pcm_uframes_t)avail < pcm->xfer_align)) {
if (pcm->mode & SND_PCM_NONBLOCK) { if (pcm->mode & SND_PCM_NONBLOCK) {
err = -EAGAIN; err = -EAGAIN;
goto _end; goto _end;
@ -5774,13 +5818,6 @@ snd_pcm_sframes_t snd_pcm_read_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_
offset += frames; offset += frames;
size -= frames; size -= frames;
xfer += frames; xfer += frames;
#if 0
state = snd_pcm_state(pcm);
if (state == SND_PCM_STATE_XRUN) {
err = -EPIPE;
goto _end;
}
#endif
} }
_end: _end:
return xfer > 0 ? (snd_pcm_sframes_t) xfer : err; return xfer > 0 ? (snd_pcm_sframes_t) xfer : err;
@ -5805,6 +5842,8 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area
break; break;
case SND_PCM_STATE_XRUN: case SND_PCM_STATE_XRUN:
return -EPIPE; return -EPIPE;
case SND_PCM_STATE_SUSPENDED:
return -ESTRPIPE;
default: default:
return -EBADFD; return -EBADFD;
} }
@ -5824,15 +5863,9 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area
if (avail < 0) { if (avail < 0) {
err = avail; err = avail;
goto _end; goto _end;
}
if (state == SND_PCM_STATE_PAUSED ||
state == SND_PCM_STATE_PREPARED) {
if ((snd_pcm_uframes_t)avail < pcm->xfer_align) {
err = -EPIPE;
goto _end;
}
} else if (((snd_pcm_uframes_t)avail < pcm->avail_min && size > (snd_pcm_uframes_t)avail) || } else if (((snd_pcm_uframes_t)avail < pcm->avail_min && size > (snd_pcm_uframes_t)avail) ||
(size >= pcm->xfer_align && (snd_pcm_uframes_t)avail < pcm->xfer_align)) { (size >= pcm->xfer_align && (snd_pcm_uframes_t)avail < pcm->xfer_align)) {
if (pcm->mode & SND_PCM_NONBLOCK) { if (pcm->mode & SND_PCM_NONBLOCK) {
err = -EAGAIN; err = -EAGAIN;
goto _end; goto _end;
@ -5858,13 +5891,6 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area
offset += frames; offset += frames;
size -= frames; size -= frames;
xfer += frames; xfer += frames;
#if 0
state = snd_pcm_state(pcm);
if (state == SND_PCM_STATE_XRUN) {
err = -EPIPE;
goto _end;
}
#endif
if (state == SND_PCM_STATE_PREPARED) { if (state == SND_PCM_STATE_PREPARED) {
snd_pcm_sframes_t hw_avail = pcm->buffer_size - avail; snd_pcm_sframes_t hw_avail = pcm->buffer_size - avail;
hw_avail += frames; hw_avail += frames;

View file

@ -162,6 +162,12 @@ static snd_pcm_state_t snd_pcm_file_state(snd_pcm_t *pcm)
return snd_pcm_state(file->slave); return snd_pcm_state(file->slave);
} }
static int snd_pcm_file_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp)
{
snd_pcm_file_t *file = pcm->private_data;
return snd_pcm_avail(file->slave, availp);
}
static int snd_pcm_file_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) static int snd_pcm_file_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{ {
snd_pcm_file_t *file = pcm->private_data; snd_pcm_file_t *file = pcm->private_data;
@ -406,6 +412,7 @@ static snd_pcm_ops_t snd_pcm_file_ops = {
static snd_pcm_fast_ops_t snd_pcm_file_fast_ops = { static snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
status: snd_pcm_file_status, status: snd_pcm_file_status,
state: snd_pcm_file_state, state: snd_pcm_file_state,
avail: snd_pcm_file_avail,
delay: snd_pcm_file_delay, delay: snd_pcm_file_delay,
prepare: snd_pcm_file_prepare, prepare: snd_pcm_file_prepare,
reset: snd_pcm_file_reset, reset: snd_pcm_file_reset,

View file

@ -116,6 +116,12 @@ static snd_pcm_state_t snd_pcm_hooks_state(snd_pcm_t *pcm)
return snd_pcm_state(h->slave); return snd_pcm_state(h->slave);
} }
static int snd_pcm_hooks_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp)
{
snd_pcm_hooks_t *h = pcm->private_data;
return snd_pcm_avail(h->slave, availp);
}
static int snd_pcm_hooks_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) static int snd_pcm_hooks_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{ {
snd_pcm_hooks_t *h = pcm->private_data; snd_pcm_hooks_t *h = pcm->private_data;
@ -292,6 +298,7 @@ static snd_pcm_ops_t snd_pcm_hooks_ops = {
static snd_pcm_fast_ops_t snd_pcm_hooks_fast_ops = { static snd_pcm_fast_ops_t snd_pcm_hooks_fast_ops = {
status: snd_pcm_hooks_status, status: snd_pcm_hooks_status,
state: snd_pcm_hooks_state, state: snd_pcm_hooks_state,
avail: snd_pcm_hooks_avail,
delay: snd_pcm_hooks_delay, delay: snd_pcm_hooks_delay,
prepare: snd_pcm_hooks_prepare, prepare: snd_pcm_hooks_prepare,
reset: snd_pcm_hooks_reset, reset: snd_pcm_hooks_reset,

View file

@ -77,9 +77,11 @@ struct sndrv_pcm_hw_params_old {
#define SND_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old) #define SND_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old)
#define SND_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old) #define SND_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old)
#define SND_PCM_IOCTL_AVAIL _IOR('A', 0x22, sndrv_pcm_uframes_t)
#define SND_PCM_IOCTL_XRUN _IO ('A', 0x48) #define SND_PCM_IOCTL_XRUN _IO ('A', 0x48)
static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params); static int use_old_hw_params_ioctl(int fd, unsigned int cmd, snd_pcm_hw_params_t *params);
static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm);
/* /*
* *
@ -101,7 +103,7 @@ typedef struct {
#define SNDRV_FILE_PCM_STREAM_PLAYBACK "/dev/snd/pcmC%iD%ip" #define SNDRV_FILE_PCM_STREAM_PLAYBACK "/dev/snd/pcmC%iD%ip"
#define SNDRV_FILE_PCM_STREAM_CAPTURE "/dev/snd/pcmC%iD%ic" #define SNDRV_FILE_PCM_STREAM_CAPTURE "/dev/snd/pcmC%iD%ic"
#define SNDRV_PCM_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 2) #define SNDRV_PCM_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 3)
/* update appl_ptr with driver */ /* update appl_ptr with driver */
#define UPDATE_SHADOW_PTR(hw) \ #define UPDATE_SHADOW_PTR(hw) \
@ -393,6 +395,33 @@ static int snd_pcm_hw_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
return 0; return 0;
} }
static int snd_pcm_hw_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp)
{
snd_pcm_hw_t *hw = pcm->private_data;
int fd = hw->fd;
if (SNDRV_PROTOCOL_VERSION(2, 0, 3) <= hw->version) {
if (ioctl(fd, SND_PCM_IOCTL_AVAIL, availp) < 0) {
// SYSERR("SND_PCM_IOCTL_AVAIL failed");
return -errno;
}
} else {
snd_pcm_sframes_t delay;
int err = snd_pcm_hw_delay(pcm, &delay);
if (err < 0) {
delay = snd_pcm_hw_avail_update(pcm);
if (delay < 0)
return delay;
*availp = delay;
} else {
delay = pcm->stream == SND_PCM_STREAM_PLAYBACK ? pcm->buffer_size - delay : delay;
if (delay < 0)
delay = 0;
*availp = delay;
}
}
return 0;
}
static int snd_pcm_hw_prepare(snd_pcm_t *pcm) static int snd_pcm_hw_prepare(snd_pcm_t *pcm)
{ {
snd_pcm_hw_t *hw = pcm->private_data; snd_pcm_hw_t *hw = pcm->private_data;
@ -757,6 +786,7 @@ static snd_pcm_ops_t snd_pcm_hw_ops = {
static snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = { static snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = {
status: snd_pcm_hw_status, status: snd_pcm_hw_status,
state: snd_pcm_hw_state, state: snd_pcm_hw_state,
avail: snd_pcm_hw_avail,
delay: snd_pcm_hw_delay, delay: snd_pcm_hw_delay,
prepare: snd_pcm_hw_prepare, prepare: snd_pcm_hw_prepare,
reset: snd_pcm_hw_reset, reset: snd_pcm_hw_reset,

View file

@ -144,6 +144,7 @@ typedef struct {
int (*drain)(snd_pcm_t *pcm); int (*drain)(snd_pcm_t *pcm);
int (*pause)(snd_pcm_t *pcm, int enable); int (*pause)(snd_pcm_t *pcm, int enable);
snd_pcm_state_t (*state)(snd_pcm_t *pcm); snd_pcm_state_t (*state)(snd_pcm_t *pcm);
int (*avail)(snd_pcm_t *pcm, snd_pcm_uframes_t *availp);
int (*delay)(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp); int (*delay)(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp);
int (*resume)(snd_pcm_t *pcm); int (*resume)(snd_pcm_t *pcm);
snd_pcm_sframes_t (*rewind)(snd_pcm_t *pcm, snd_pcm_uframes_t frames); snd_pcm_sframes_t (*rewind)(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
@ -323,31 +324,12 @@ static inline snd_pcm_uframes_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm)
static inline snd_pcm_uframes_t snd_pcm_mmap_playback_delay(snd_pcm_t *pcm) static inline snd_pcm_uframes_t snd_pcm_mmap_playback_delay(snd_pcm_t *pcm)
{ {
snd_pcm_state_t state = snd_pcm_state(pcm);
switch (state) {
case SND_PCM_STATE_RUNNING:
case SND_PCM_STATE_DRAINING:
return snd_pcm_mmap_playback_hw_avail(pcm); return snd_pcm_mmap_playback_hw_avail(pcm);
case SND_PCM_STATE_XRUN:
return -EPIPE;
default:
return -EBADFD;
}
} }
static inline snd_pcm_uframes_t snd_pcm_mmap_capture_delay(snd_pcm_t *pcm) static inline snd_pcm_uframes_t snd_pcm_mmap_capture_delay(snd_pcm_t *pcm)
{ {
snd_pcm_state_t state = snd_pcm_state(pcm);
switch (state) {
case SND_PCM_STATE_RUNNING:
return snd_pcm_mmap_capture_hw_avail(pcm); return snd_pcm_mmap_capture_hw_avail(pcm);
case SND_PCM_STATE_XRUN:
return -EPIPE;
default:
return -EBADFD;
}
} }
static inline snd_pcm_sframes_t snd_pcm_mmap_delay(snd_pcm_t *pcm) static inline snd_pcm_sframes_t snd_pcm_mmap_delay(snd_pcm_t *pcm)

View file

@ -319,6 +319,12 @@ static snd_pcm_state_t snd_pcm_meter_state(snd_pcm_t *pcm)
return snd_pcm_state(meter->slave); return snd_pcm_state(meter->slave);
} }
static int snd_pcm_meter_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp)
{
snd_pcm_meter_t *meter = pcm->private_data;
return snd_pcm_avail(meter->slave, availp);
}
static int snd_pcm_meter_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) static int snd_pcm_meter_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{ {
snd_pcm_meter_t *meter = pcm->private_data; snd_pcm_meter_t *meter = pcm->private_data;
@ -593,6 +599,7 @@ static snd_pcm_ops_t snd_pcm_meter_ops = {
static snd_pcm_fast_ops_t snd_pcm_meter_fast_ops = { static snd_pcm_fast_ops_t snd_pcm_meter_fast_ops = {
status: snd_pcm_meter_status, status: snd_pcm_meter_status,
state: snd_pcm_meter_state, state: snd_pcm_meter_state,
avail: snd_pcm_meter_avail,
delay: snd_pcm_meter_delay, delay: snd_pcm_meter_delay,
prepare: snd_pcm_meter_prepare, prepare: snd_pcm_meter_prepare,
reset: snd_pcm_meter_reset, reset: snd_pcm_meter_reset,

View file

@ -351,6 +351,13 @@ static snd_pcm_state_t snd_pcm_multi_state(snd_pcm_t *pcm)
return snd_pcm_state(slave); return snd_pcm_state(slave);
} }
static int snd_pcm_multi_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp)
{
snd_pcm_multi_t *multi = pcm->private_data;
snd_pcm_t *slave = multi->slaves[0].pcm;
return snd_pcm_avail(slave, availp);
}
static int snd_pcm_multi_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) static int snd_pcm_multi_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{ {
snd_pcm_multi_t *multi = pcm->private_data; snd_pcm_multi_t *multi = pcm->private_data;
@ -594,6 +601,7 @@ static snd_pcm_ops_t snd_pcm_multi_ops = {
static snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = { static snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = {
status: snd_pcm_multi_status, status: snd_pcm_multi_status,
state: snd_pcm_multi_state, state: snd_pcm_multi_state,
avail: snd_pcm_multi_avail,
delay: snd_pcm_multi_delay, delay: snd_pcm_multi_delay,
prepare: snd_pcm_multi_prepare, prepare: snd_pcm_multi_prepare,
reset: snd_pcm_multi_reset, reset: snd_pcm_multi_reset,

View file

@ -102,6 +102,12 @@ static snd_pcm_state_t snd_pcm_null_state(snd_pcm_t *pcm)
return null->state; return null->state;
} }
static int snd_pcm_null_avail(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_uframes_t *availp)
{
*availp = pcm->buffer_size;
return 0;
}
static int snd_pcm_null_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t *delayp) static int snd_pcm_null_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t *delayp)
{ {
*delayp = 0; *delayp = 0;
@ -320,6 +326,7 @@ static snd_pcm_ops_t snd_pcm_null_ops = {
static snd_pcm_fast_ops_t snd_pcm_null_fast_ops = { static snd_pcm_fast_ops_t snd_pcm_null_fast_ops = {
status: snd_pcm_null_status, status: snd_pcm_null_status,
state: snd_pcm_null_state, state: snd_pcm_null_state,
avail: snd_pcm_null_avail,
delay: snd_pcm_null_delay, delay: snd_pcm_null_delay,
prepare: snd_pcm_null_prepare, prepare: snd_pcm_null_prepare,
reset: snd_pcm_null_reset, reset: snd_pcm_null_reset,

View file

@ -188,6 +188,19 @@ snd_pcm_state_t snd_pcm_plugin_state(snd_pcm_t *pcm)
return snd_pcm_state(plugin->slave); return snd_pcm_state(plugin->slave);
} }
int snd_pcm_plugin_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp)
{
snd_pcm_plugin_t *plugin = pcm->private_data;
snd_pcm_uframes_t sd;
int err = snd_pcm_avail(plugin->slave, &sd);
if (err < 0)
return err;
if (plugin->client_frames)
sd = plugin->client_frames(pcm, sd);
*availp = sd;
return 0;
}
int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{ {
snd_pcm_plugin_t *plugin = pcm->private_data; snd_pcm_plugin_t *plugin = pcm->private_data;
@ -197,7 +210,7 @@ int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
return err; return err;
if (plugin->client_frames) if (plugin->client_frames)
sd = plugin->client_frames(pcm, sd); sd = plugin->client_frames(pcm, sd);
*delayp = sd + snd_pcm_mmap_delay(pcm); *delayp = sd;
return 0; return 0;
} }
@ -627,6 +640,7 @@ int snd_pcm_plugin_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = { snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = {
status: snd_pcm_plugin_status, status: snd_pcm_plugin_status,
state: snd_pcm_plugin_state, state: snd_pcm_plugin_state,
avail: snd_pcm_plugin_avail,
delay: snd_pcm_plugin_delay, delay: snd_pcm_plugin_delay,
prepare: snd_pcm_plugin_prepare, prepare: snd_pcm_plugin_prepare,
reset: snd_pcm_plugin_reset, reset: snd_pcm_plugin_reset,

View file

@ -713,12 +713,34 @@ static snd_pcm_state_t snd_pcm_share_state(snd_pcm_t *pcm)
return share->state; return share->state;
} }
static int _snd_pcm_share_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp)
{
snd_pcm_share_t *share = pcm->private_data;
snd_pcm_share_slave_t *slave = share->slave;
switch (share->state) {
case SND_PCM_STATE_XRUN:
return -EPIPE;
default:
break;
}
return snd_pcm_avail(slave->pcm, availp);
}
static int snd_pcm_share_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp)
{
snd_pcm_share_t *share = pcm->private_data;
snd_pcm_share_slave_t *slave = share->slave;
int err;
Pthread_mutex_lock(&slave->mutex);
err = _snd_pcm_share_avail(pcm, availp);
Pthread_mutex_unlock(&slave->mutex);
return err;
}
static int _snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) static int _snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{ {
snd_pcm_share_t *share = pcm->private_data; snd_pcm_share_t *share = pcm->private_data;
snd_pcm_share_slave_t *slave = share->slave; snd_pcm_share_slave_t *slave = share->slave;
int err = 0;
snd_pcm_sframes_t sd;
switch (share->state) { switch (share->state) {
case SND_PCM_STATE_XRUN: case SND_PCM_STATE_XRUN:
return -EPIPE; return -EPIPE;
@ -731,11 +753,7 @@ static int _snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
default: default:
return -EBADFD; return -EBADFD;
} }
err = snd_pcm_delay(slave->pcm, &sd); return snd_pcm_delay(slave->pcm, delayp);
if (err < 0)
return err;
*delayp = sd + snd_pcm_mmap_delay(pcm);
return 0;
} }
static int snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) static int snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
@ -1215,6 +1233,7 @@ static snd_pcm_ops_t snd_pcm_share_ops = {
static snd_pcm_fast_ops_t snd_pcm_share_fast_ops = { static snd_pcm_fast_ops_t snd_pcm_share_fast_ops = {
status: snd_pcm_share_status, status: snd_pcm_share_status,
state: snd_pcm_share_state, state: snd_pcm_share_state,
avail: snd_pcm_share_avail,
delay: snd_pcm_share_delay, delay: snd_pcm_share_delay,
prepare: snd_pcm_share_prepare, prepare: snd_pcm_share_prepare,
reset: snd_pcm_share_reset, reset: snd_pcm_share_reset,

View file

@ -443,6 +443,19 @@ static snd_pcm_state_t snd_pcm_shm_state(snd_pcm_t *pcm)
return snd_pcm_shm_action(pcm); return snd_pcm_shm_action(pcm);
} }
static int snd_pcm_shm_avail(snd_pcm_t *pcm, snd_pcm_uframes_t *availp)
{
snd_pcm_shm_t *shm = pcm->private_data;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
int err;
ctrl->cmd = SND_PCM_IOCTL_AVAIL;
err = snd_pcm_shm_action(pcm);
if (err < 0)
return err;
*availp = ctrl->u.avail.frames;
return err;
}
static int snd_pcm_shm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) static int snd_pcm_shm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{ {
snd_pcm_shm_t *shm = pcm->private_data; snd_pcm_shm_t *shm = pcm->private_data;