mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-01 22:58:49 -04:00
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:
parent
25e41cf1e8
commit
e859cf2644
11 changed files with 189 additions and 69 deletions
102
src/pcm/pcm.c
102
src/pcm/pcm.c
|
|
@ -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)) {
|
(size >= pcm->xfer_align && (snd_pcm_uframes_t)avail < pcm->xfer_align)) {
|
||||||
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)) {
|
|
||||||
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;
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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_XRUN _IO('A', 0x48)
|
#define SND_PCM_IOCTL_AVAIL _IOR('A', 0x22, sndrv_pcm_uframes_t)
|
||||||
|
#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,
|
||||||
|
|
|
||||||
|
|
@ -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);
|
return snd_pcm_mmap_playback_hw_avail(pcm);
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case SND_PCM_STATE_RUNNING:
|
|
||||||
case SND_PCM_STATE_DRAINING:
|
|
||||||
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);
|
return snd_pcm_mmap_capture_hw_avail(pcm);
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case SND_PCM_STATE_RUNNING:
|
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue