mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Implemented snd_pcm_sw_params_(set|get)_period_event for interrupt wakeup like behaviour
Actually, PCM timer is used as source for poll(). It might be optimized in the kernel code later.
This commit is contained in:
parent
c88672d86f
commit
8aaccc9484
6 changed files with 231 additions and 7 deletions
|
|
@ -717,6 +717,8 @@ int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *param
|
||||||
int snd_pcm_sw_params_get_tstamp_mode(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_t *val);
|
int snd_pcm_sw_params_get_tstamp_mode(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_t *val);
|
||||||
int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
|
int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
|
||||||
int snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val);
|
int snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val);
|
||||||
|
int snd_pcm_sw_params_set_period_event(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, int val);
|
||||||
|
int snd_pcm_sw_params_get_period_event(const snd_pcm_sw_params_t *params, int *val);
|
||||||
int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
|
int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
|
||||||
int snd_pcm_sw_params_get_start_threshold(const snd_pcm_sw_params_t *paramsm, snd_pcm_uframes_t *val);
|
int snd_pcm_sw_params_get_start_threshold(const snd_pcm_sw_params_t *paramsm, snd_pcm_uframes_t *val);
|
||||||
int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
|
int snd_pcm_sw_params_set_stop_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
|
||||||
|
|
|
||||||
|
|
@ -396,7 +396,8 @@ struct sndrv_pcm_sw_params {
|
||||||
sndrv_pcm_uframes_t silence_threshold; /* min distance from noise for silence filling */
|
sndrv_pcm_uframes_t silence_threshold; /* min distance from noise for silence filling */
|
||||||
sndrv_pcm_uframes_t silence_size; /* silence block size */
|
sndrv_pcm_uframes_t silence_size; /* silence block size */
|
||||||
sndrv_pcm_uframes_t boundary; /* pointers wrap point */
|
sndrv_pcm_uframes_t boundary; /* pointers wrap point */
|
||||||
unsigned char reserved[64]; /* reserved for future */
|
unsigned char reserved[60]; /* reserved for future */
|
||||||
|
unsigned int period_event; /* for alsa-lib implementation */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sndrv_pcm_channel_info {
|
struct sndrv_pcm_channel_info {
|
||||||
|
|
|
||||||
|
|
@ -879,6 +879,7 @@ int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
|
||||||
pcm->tstamp_mode = params->tstamp_mode;
|
pcm->tstamp_mode = params->tstamp_mode;
|
||||||
pcm->period_step = params->period_step;
|
pcm->period_step = params->period_step;
|
||||||
pcm->avail_min = params->avail_min;
|
pcm->avail_min = params->avail_min;
|
||||||
|
pcm->period_event = params->period_event;
|
||||||
pcm->start_threshold = params->start_threshold;
|
pcm->start_threshold = params->start_threshold;
|
||||||
pcm->stop_threshold = params->stop_threshold;
|
pcm->stop_threshold = params->stop_threshold;
|
||||||
pcm->silence_threshold = params->silence_threshold;
|
pcm->silence_threshold = params->silence_threshold;
|
||||||
|
|
@ -1847,6 +1848,7 @@ int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, snd_output_t *out)
|
||||||
snd_output_printf(out, " tstamp_mode : %s\n", snd_pcm_tstamp_mode_name(pcm->tstamp_mode));
|
snd_output_printf(out, " tstamp_mode : %s\n", snd_pcm_tstamp_mode_name(pcm->tstamp_mode));
|
||||||
snd_output_printf(out, " period_step : %d\n", pcm->period_step);
|
snd_output_printf(out, " period_step : %d\n", pcm->period_step);
|
||||||
snd_output_printf(out, " avail_min : %ld\n", pcm->avail_min);
|
snd_output_printf(out, " avail_min : %ld\n", pcm->avail_min);
|
||||||
|
snd_output_printf(out, " period_event : %i\n", pcm->period_event);
|
||||||
snd_output_printf(out, " start_threshold : %ld\n", pcm->start_threshold);
|
snd_output_printf(out, " start_threshold : %ld\n", pcm->start_threshold);
|
||||||
snd_output_printf(out, " stop_threshold : %ld\n", pcm->stop_threshold);
|
snd_output_printf(out, " stop_threshold : %ld\n", pcm->stop_threshold);
|
||||||
snd_output_printf(out, " silence_threshold: %ld\n", pcm->silence_threshold);
|
snd_output_printf(out, " silence_threshold: %ld\n", pcm->silence_threshold);
|
||||||
|
|
@ -5364,6 +5366,7 @@ int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
|
||||||
params->period_step = pcm->period_step;
|
params->period_step = pcm->period_step;
|
||||||
params->sleep_min = 0;
|
params->sleep_min = 0;
|
||||||
params->avail_min = pcm->avail_min;
|
params->avail_min = pcm->avail_min;
|
||||||
|
params->period_event = pcm->period_event;
|
||||||
params->xfer_align = 1;
|
params->xfer_align = 1;
|
||||||
params->start_threshold = pcm->start_threshold;
|
params->start_threshold = pcm->start_threshold;
|
||||||
params->stop_threshold = pcm->stop_threshold;
|
params->stop_threshold = pcm->stop_threshold;
|
||||||
|
|
@ -5659,6 +5662,34 @@ int snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t *params, snd_pcm_u
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set period event inside a software configuration container
|
||||||
|
* \param pcm PCM handle
|
||||||
|
* \param params Software configuration container
|
||||||
|
* \param val 0 = disable period event, 1 = enable period event
|
||||||
|
* \return 0 otherwise a negative error code
|
||||||
|
*
|
||||||
|
* An poll (select) wakeup event is raised if enabled.
|
||||||
|
*/
|
||||||
|
int snd_pcm_sw_params_set_period_event(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, int val)
|
||||||
|
{
|
||||||
|
assert(pcm && params);
|
||||||
|
params->period_event = val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get period event from a software configuration container
|
||||||
|
* \param params Software configuration container
|
||||||
|
* \param val returned period event state
|
||||||
|
* \return 0 otherwise a negative error code
|
||||||
|
*/
|
||||||
|
int snd_pcm_sw_params_get_period_event(const snd_pcm_sw_params_t *params, int *val)
|
||||||
|
{
|
||||||
|
assert(params && val);
|
||||||
|
*val = params->period_event;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief (DEPRECATED) Set xfer align inside a software configuration container
|
* \brief (DEPRECATED) Set xfer align inside a software configuration container
|
||||||
|
|
|
||||||
173
src/pcm/pcm_hw.c
173
src/pcm/pcm_hw.c
|
|
@ -39,6 +39,7 @@
|
||||||
#include <sys/shm.h>
|
#include <sys/shm.h>
|
||||||
#include "pcm_local.h"
|
#include "pcm_local.h"
|
||||||
#include "../control/control_local.h"
|
#include "../control/control_local.h"
|
||||||
|
#include "../timer/timer_local.h"
|
||||||
|
|
||||||
//#define DEBUG_RW /* use to debug readi/writei/readn/writen */
|
//#define DEBUG_RW /* use to debug readi/writei/readn/writen */
|
||||||
//#define DEBUG_MMAP /* debug mmap_commit */
|
//#define DEBUG_MMAP /* debug mmap_commit */
|
||||||
|
|
@ -79,6 +80,8 @@ struct sndrv_pcm_hw_params_old {
|
||||||
|
|
||||||
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);
|
static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm);
|
||||||
|
static snd_pcm_fast_ops_t snd_pcm_hw_fast_ops;
|
||||||
|
static snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
|
|
@ -94,6 +97,10 @@ typedef struct {
|
||||||
struct sndrv_pcm_sync_ptr *sync_ptr;
|
struct sndrv_pcm_sync_ptr *sync_ptr;
|
||||||
snd_pcm_uframes_t hw_ptr;
|
snd_pcm_uframes_t hw_ptr;
|
||||||
snd_pcm_uframes_t appl_ptr;
|
snd_pcm_uframes_t appl_ptr;
|
||||||
|
int period_event;
|
||||||
|
snd_timer_t *period_timer;
|
||||||
|
struct pollfd period_timer_pfd;
|
||||||
|
int period_timer_need_poll;
|
||||||
/* restricted parameters */
|
/* restricted parameters */
|
||||||
snd_pcm_format_t format;
|
snd_pcm_format_t format;
|
||||||
int rate;
|
int rate;
|
||||||
|
|
@ -139,6 +146,53 @@ static inline int sync_ptr(snd_pcm_hw_t *hw, unsigned int flags)
|
||||||
return hw->sync_ptr ? sync_ptr1(hw, flags) : 0;
|
return hw->sync_ptr ? sync_ptr1(hw, flags) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int snd_pcm_hw_clear_timer_queue(snd_pcm_hw_t *hw)
|
||||||
|
{
|
||||||
|
if (hw->period_timer_need_poll) {
|
||||||
|
while (poll(&hw->period_timer_pfd, 1, 0) > 0) {
|
||||||
|
snd_timer_tread_t rbuf[4];
|
||||||
|
snd_timer_read(hw->period_timer, rbuf, sizeof(rbuf));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
snd_timer_tread_t rbuf[4];
|
||||||
|
snd_timer_read(hw->period_timer, rbuf, sizeof(rbuf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int snd_pcm_hw_poll_descriptors_count(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int snd_pcm_hw_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
|
||||||
|
{
|
||||||
|
snd_pcm_hw_t *hw = pcm->private_data;
|
||||||
|
|
||||||
|
if (space < 2)
|
||||||
|
return -ENOMEM;
|
||||||
|
pfds[0].fd = hw->fd;
|
||||||
|
pfds[0].events = pcm->poll_events | POLLERR | POLLNVAL;
|
||||||
|
pfds[1].fd = hw->period_timer_pfd.fd;
|
||||||
|
pfds[1].events = POLLIN | POLLERR | POLLNVAL;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int snd_pcm_hw_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned nfds, unsigned short *revents)
|
||||||
|
{
|
||||||
|
snd_pcm_hw_t *hw = pcm->private_data;
|
||||||
|
unsigned int events;
|
||||||
|
|
||||||
|
if (nfds != 2 || pfds[0].fd != hw->fd || pfds[1].fd != hw->period_timer_pfd.fd)
|
||||||
|
return -EINVAL;
|
||||||
|
events = pfds[0].revents;
|
||||||
|
if (pfds[1].revents & POLLIN) {
|
||||||
|
snd_pcm_hw_clear_timer_queue(hw);
|
||||||
|
events |= pcm->poll_events & ~(POLLERR|POLLNVAL);
|
||||||
|
}
|
||||||
|
*revents = events;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock)
|
static int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock)
|
||||||
{
|
{
|
||||||
long flags;
|
long flags;
|
||||||
|
|
@ -293,16 +347,94 @@ static int snd_pcm_hw_hw_free(snd_pcm_t *pcm)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void snd_pcm_hw_close_timer(snd_pcm_hw_t *hw)
|
||||||
|
{
|
||||||
|
if (hw->period_timer) {
|
||||||
|
snd_timer_close(hw->period_timer);
|
||||||
|
hw->period_timer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int snd_pcm_hw_change_timer(snd_pcm_t *pcm, int enable)
|
||||||
|
{
|
||||||
|
snd_pcm_hw_t *hw = pcm->private_data;
|
||||||
|
snd_timer_params_t *params;
|
||||||
|
unsigned int suspend, resume;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
snd_timer_params_alloca(¶ms);
|
||||||
|
err = snd_timer_hw_open(&hw->period_timer, "hw-pcm-period-event", SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE, hw->card, hw->device, hw->subdevice, SND_TIMER_OPEN_NONBLOCK | SND_TIMER_OPEN_TREAD);
|
||||||
|
if (err < 0) {
|
||||||
|
err = snd_timer_hw_open(&hw->period_timer, "hw-pcm-period-event", SND_TIMER_CLASS_PCM, SND_TIMER_SCLASS_NONE, hw->card, hw->device, hw->subdevice, SND_TIMER_OPEN_NONBLOCK);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (snd_timer_poll_descriptors_count(hw->period_timer) != 1) {
|
||||||
|
snd_pcm_hw_close_timer(hw);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
hw->period_timer_pfd.events = POLLIN;
|
||||||
|
hw->period_timer_pfd.revents = 0;
|
||||||
|
snd_timer_poll_descriptors(hw->period_timer, &hw->period_timer_pfd, 1);
|
||||||
|
hw->period_timer_need_poll = 0;
|
||||||
|
suspend = 1<<SND_TIMER_EVENT_MSUSPEND;
|
||||||
|
resume = 1<<SND_TIMER_EVENT_MRESUME;
|
||||||
|
/*
|
||||||
|
* hacks for older kernel drivers
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int ver = 0;
|
||||||
|
ioctl(hw->period_timer_pfd.fd, SNDRV_TIMER_IOCTL_PVERSION, &ver);
|
||||||
|
/* In older versions, check via poll before read() is needed
|
||||||
|
* because of the confliction between TIMER_START and
|
||||||
|
* FIONBIO ioctls.
|
||||||
|
*/
|
||||||
|
if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 4))
|
||||||
|
hw->period_timer_need_poll = 1;
|
||||||
|
/*
|
||||||
|
* In older versions, timer uses pause events instead
|
||||||
|
* suspend/resume events.
|
||||||
|
*/
|
||||||
|
if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 5)) {
|
||||||
|
suspend = 1<<SND_TIMER_EVENT_MPAUSE;
|
||||||
|
resume = 1<<SND_TIMER_EVENT_MCONTINUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snd_timer_params_set_auto_start(params, 1);
|
||||||
|
snd_timer_params_set_ticks(params, 1);
|
||||||
|
snd_timer_params_set_filter(params, (1<<SND_TIMER_EVENT_TICK) |
|
||||||
|
suspend | resume);
|
||||||
|
err = snd_timer_params(hw->period_timer, params);
|
||||||
|
if (err < 0) {
|
||||||
|
snd_pcm_hw_close_timer(hw);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
err = snd_timer_start(hw->period_timer);
|
||||||
|
if (err < 0) {
|
||||||
|
snd_pcm_hw_close_timer(hw);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
pcm->fast_ops = &snd_pcm_hw_fast_ops_timer;
|
||||||
|
} else {
|
||||||
|
snd_pcm_hw_close_timer(hw);
|
||||||
|
pcm->fast_ops = &snd_pcm_hw_fast_ops;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
|
static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
|
||||||
{
|
{
|
||||||
snd_pcm_hw_t *hw = pcm->private_data;
|
snd_pcm_hw_t *hw = pcm->private_data;
|
||||||
int fd = hw->fd, err;
|
int fd = hw->fd, err;
|
||||||
|
int old_period_event = params->period_event;
|
||||||
|
params->period_event = 0;
|
||||||
if ((snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode &&
|
if ((snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode &&
|
||||||
params->period_step == pcm->period_step &&
|
params->period_step == pcm->period_step &&
|
||||||
params->start_threshold == pcm->start_threshold &&
|
params->start_threshold == pcm->start_threshold &&
|
||||||
params->stop_threshold == pcm->stop_threshold &&
|
params->stop_threshold == pcm->stop_threshold &&
|
||||||
params->silence_threshold == pcm->silence_threshold &&
|
params->silence_threshold == pcm->silence_threshold &&
|
||||||
params->silence_size == pcm->silence_size) {
|
params->silence_size == pcm->silence_size &&
|
||||||
|
old_period_event == hw->period_event) {
|
||||||
hw->mmap_control->avail_min = params->avail_min;
|
hw->mmap_control->avail_min = params->avail_min;
|
||||||
return sync_ptr(hw, 0);
|
return sync_ptr(hw, 0);
|
||||||
}
|
}
|
||||||
|
|
@ -311,7 +443,14 @@ static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
|
||||||
SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed");
|
SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
params->period_event = old_period_event;
|
||||||
hw->mmap_control->avail_min = params->avail_min;
|
hw->mmap_control->avail_min = params->avail_min;
|
||||||
|
if (hw->period_event != old_period_event) {
|
||||||
|
err = snd_pcm_hw_change_timer(pcm, old_period_event);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
hw->period_event = old_period_event;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -480,6 +619,7 @@ static int snd_pcm_hw_drop(snd_pcm_t *pcm)
|
||||||
err = -errno;
|
err = -errno;
|
||||||
SYSMSG("SNDRV_PCM_IOCTL_DROP failed");
|
SYSMSG("SNDRV_PCM_IOCTL_DROP failed");
|
||||||
return err;
|
return err;
|
||||||
|
} else {
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -945,6 +1085,37 @@ static snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = {
|
||||||
.poll_revents = NULL,
|
.poll_revents = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static snd_pcm_fast_ops_t snd_pcm_hw_fast_ops_timer = {
|
||||||
|
.status = snd_pcm_hw_status,
|
||||||
|
.state = snd_pcm_hw_state,
|
||||||
|
.hwsync = snd_pcm_hw_hwsync,
|
||||||
|
.delay = snd_pcm_hw_delay,
|
||||||
|
.prepare = snd_pcm_hw_prepare,
|
||||||
|
.reset = snd_pcm_hw_reset,
|
||||||
|
.start = snd_pcm_hw_start,
|
||||||
|
.drop = snd_pcm_hw_drop,
|
||||||
|
.drain = snd_pcm_hw_drain,
|
||||||
|
.pause = snd_pcm_hw_pause,
|
||||||
|
.rewindable = snd_pcm_hw_rewindable,
|
||||||
|
.rewind = snd_pcm_hw_rewind,
|
||||||
|
.forwardable = snd_pcm_hw_forwardable,
|
||||||
|
.forward = snd_pcm_hw_forward,
|
||||||
|
.resume = snd_pcm_hw_resume,
|
||||||
|
.link = snd_pcm_hw_link,
|
||||||
|
.link_slaves = snd_pcm_hw_link_slaves,
|
||||||
|
.unlink = snd_pcm_hw_unlink,
|
||||||
|
.writei = snd_pcm_hw_writei,
|
||||||
|
.writen = snd_pcm_hw_writen,
|
||||||
|
.readi = snd_pcm_hw_readi,
|
||||||
|
.readn = snd_pcm_hw_readn,
|
||||||
|
.avail_update = snd_pcm_hw_avail_update,
|
||||||
|
.mmap_commit = snd_pcm_hw_mmap_commit,
|
||||||
|
.htimestamp = snd_pcm_hw_htimestamp,
|
||||||
|
.poll_descriptors = snd_pcm_hw_poll_descriptors,
|
||||||
|
.poll_descriptors_count = snd_pcm_hw_poll_descriptors_count,
|
||||||
|
.poll_revents = snd_pcm_hw_poll_revents,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Creates a new hw PCM
|
* \brief Creates a new hw PCM
|
||||||
* \param pcmp Returns created PCM handle
|
* \param pcmp Returns created PCM handle
|
||||||
|
|
|
||||||
|
|
@ -195,8 +195,9 @@ struct _snd_pcm {
|
||||||
snd_pcm_tstamp_t tstamp_mode; /* timestamp mode */
|
snd_pcm_tstamp_t tstamp_mode; /* timestamp mode */
|
||||||
unsigned int period_step;
|
unsigned int period_step;
|
||||||
snd_pcm_uframes_t avail_min; /* min avail frames for wakeup */
|
snd_pcm_uframes_t avail_min; /* min avail frames for wakeup */
|
||||||
snd_pcm_uframes_t start_threshold;
|
int period_event;
|
||||||
snd_pcm_uframes_t stop_threshold;
|
snd_pcm_uframes_t start_threshold;
|
||||||
|
snd_pcm_uframes_t stop_threshold;
|
||||||
snd_pcm_uframes_t silence_threshold; /* Silence filling happens when
|
snd_pcm_uframes_t silence_threshold; /* Silence filling happens when
|
||||||
noise is nearest than this */
|
noise is nearest than this */
|
||||||
snd_pcm_uframes_t silence_size; /* Silence filling size */
|
snd_pcm_uframes_t silence_size; /* Silence filling size */
|
||||||
|
|
|
||||||
24
test/pcm.c
24
test/pcm.c
|
|
@ -19,8 +19,9 @@ static unsigned int channels = 1; /* count of channels */
|
||||||
static unsigned int buffer_time = 500000; /* ring buffer length in us */
|
static unsigned int buffer_time = 500000; /* ring buffer length in us */
|
||||||
static unsigned int period_time = 100000; /* period time in us */
|
static unsigned int period_time = 100000; /* period time in us */
|
||||||
static double freq = 440; /* sinusoidal wave frequency in Hz */
|
static double freq = 440; /* sinusoidal wave frequency in Hz */
|
||||||
static int verbose = 0; /* verbose flag */
|
static int verbose = 0; /* verbose flag */
|
||||||
static int resample = 1; /* enable alsa-lib resampling */
|
static int resample = 1; /* enable alsa-lib resampling */
|
||||||
|
static int period_event = 0; /* produce poll event after each period */
|
||||||
|
|
||||||
static snd_pcm_sframes_t buffer_size;
|
static snd_pcm_sframes_t buffer_size;
|
||||||
static snd_pcm_sframes_t period_size;
|
static snd_pcm_sframes_t period_size;
|
||||||
|
|
@ -172,11 +173,20 @@ static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
/* allow the transfer when at least period_size samples can be processed */
|
/* allow the transfer when at least period_size samples can be processed */
|
||||||
err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_size);
|
/* or disable this mechanism when period event is enabled (aka interrupt like style processing) */
|
||||||
|
err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_event ? buffer_size : period_size);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
printf("Unable to set avail min for playback: %s\n", snd_strerror(err));
|
printf("Unable to set avail min for playback: %s\n", snd_strerror(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
/* enable period events when requested */
|
||||||
|
if (period_event) {
|
||||||
|
err = snd_pcm_sw_params_set_period_event(handle, swparams, 1);
|
||||||
|
if (err < 0) {
|
||||||
|
printf("Unable to set period event: %s\n", snd_strerror(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* write the parameters to the playback device */
|
/* write the parameters to the playback device */
|
||||||
err = snd_pcm_sw_params(handle, swparams);
|
err = snd_pcm_sw_params(handle, swparams);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
|
@ -192,6 +202,8 @@ static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams)
|
||||||
|
|
||||||
static int xrun_recovery(snd_pcm_t *handle, int err)
|
static int xrun_recovery(snd_pcm_t *handle, int err)
|
||||||
{
|
{
|
||||||
|
if (verbose)
|
||||||
|
printf("stream recovery\n");
|
||||||
if (err == -EPIPE) { /* under-run */
|
if (err == -EPIPE) { /* under-run */
|
||||||
err = snd_pcm_prepare(handle);
|
err = snd_pcm_prepare(handle);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
|
@ -711,6 +723,8 @@ static void help(void)
|
||||||
"-m,--method transfer method\n"
|
"-m,--method transfer method\n"
|
||||||
"-o,--format sample format\n"
|
"-o,--format sample format\n"
|
||||||
"-v,--verbose show the PCM setup parameters\n"
|
"-v,--verbose show the PCM setup parameters\n"
|
||||||
|
"-n,--noresample do not resample\n"
|
||||||
|
"-e,--pevent enable poll event after each period\n"
|
||||||
"\n");
|
"\n");
|
||||||
printf("Recognized sample formats are:");
|
printf("Recognized sample formats are:");
|
||||||
for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) {
|
for (k = 0; k < SND_PCM_FORMAT_LAST; ++k) {
|
||||||
|
|
@ -740,6 +754,7 @@ int main(int argc, char *argv[])
|
||||||
{"format", 1, NULL, 'o'},
|
{"format", 1, NULL, 'o'},
|
||||||
{"verbose", 1, NULL, 'v'},
|
{"verbose", 1, NULL, 'v'},
|
||||||
{"noresample", 1, NULL, 'n'},
|
{"noresample", 1, NULL, 'n'},
|
||||||
|
{"pevent", 1, NULL, 'e'},
|
||||||
{NULL, 0, NULL, 0},
|
{NULL, 0, NULL, 0},
|
||||||
};
|
};
|
||||||
snd_pcm_t *handle;
|
snd_pcm_t *handle;
|
||||||
|
|
@ -757,7 +772,7 @@ int main(int argc, char *argv[])
|
||||||
morehelp = 0;
|
morehelp = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
int c;
|
int c;
|
||||||
if ((c = getopt_long(argc, argv, "hD:r:c:f:b:p:m:o:vn", long_option, NULL)) < 0)
|
if ((c = getopt_long(argc, argv, "hD:r:c:f:b:p:m:o:vne", long_option, NULL)) < 0)
|
||||||
break;
|
break;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
|
|
@ -814,6 +829,9 @@ int main(int argc, char *argv[])
|
||||||
case 'n':
|
case 'n':
|
||||||
resample = 0;
|
resample = 0;
|
||||||
break;
|
break;
|
||||||
|
case 'e':
|
||||||
|
period_event = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue