case SND_PCM_IOCTL_HWSYNC:
ctrl->result = snd_pcm_hwsync(pcm);
break;
+ case SND_PCM_IOCTL_HWPTR:
+ ctrl->result = snd_pcm_hwptr(pcm, (snd_pcm_uframes_t *) &ctrl->u.hwptr.frames);
+ break;
case SNDRV_PCM_IOCTL_DELAY:
ctrl->result = snd_pcm_delay(pcm, (snd_pcm_sframes_t *) &ctrl->u.delay.frames);
break;
#define SND_PCM_IOCTL_POLL_DESCRIPTOR _IO ('A', 0xf8)
#define SND_PCM_IOCTL_HW_PTR_FD _IO ('A', 0xf9)
#define SND_PCM_IOCTL_APPL_PTR_FD _IO ('A', 0xfa)
+#define SND_PCM_IOCTL_HWPTR _IO ('A', 0xfb)
typedef struct {
snd_pcm_uframes_t ptr;
snd_pcm_hw_params_t hw_params;
snd_pcm_sw_params_t sw_params;
snd_pcm_status_t status;
+ struct {
+ snd_pcm_uframes_t frames;
+ } hwptr;
struct {
snd_pcm_uframes_t frames;
} avail;
int snd_pcm_pause(snd_pcm_t *pcm, int enable);
snd_pcm_state_t snd_pcm_state(snd_pcm_t *pcm);
int snd_pcm_hwsync(snd_pcm_t *pcm);
+int snd_pcm_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *uframes);
int snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp);
int snd_pcm_resume(snd_pcm_t *pcm);
snd_pcm_sframes_t snd_pcm_avail_update(snd_pcm_t *pcm);
local:
*;
};
+
ALSA_0.9.0rc4 {
global:
snd_pcm_hw_params_set_tick_time_first;
snd_pcm_hw_params_set_tick_time_last;
-}ALSA_0.9;
+} ALSA_0.9;
+
+ALSA_0.9.0rc8 {
+ global:
+
+ snd_pcm_hwptr;
+
+} ALSA_0.9.0rc4;
return pcm->fast_ops->hwsync(pcm->fast_op_arg);
}
+/**
+ * \brief Return hardware pointer
+ * \param pcm PCM handle
+ * \return 0 on success otherwise a negative error code
+ *
+ * The hardware pointer is in range 0 ... (boundary - 1). It contains
+ * count_of_ring_buffer_crosses * buffer_size + offset in the ring buffer.
+ *
+ * Note this function does not return the real hardware pointer.
+ * The function \link ::snd_pcm_hwsync \endlink have to be called
+ * before to obtain the real hardware position.
+ */
+#ifndef DOXYGEN
+int INTERNAL(snd_pcm_hwptr)(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr)
+#else
+int snd_pcm_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr)
+#endif
+{
+ assert(pcm);
+ assert(pcm->setup);
+ return pcm->fast_ops->hwptr(pcm->fast_op_arg, hwptr);
+}
+default_symbol_version(__snd_pcm_hwptr, snd_pcm_hwptr, ALSA_0.9.0rc8);
+
/**
* \brief Obtain delay for a running PCM handle
* \param pcm PCM handle
* \brief Application request to access a portion of direct (mmap) area
* \param pcm PCM handle
* \param areas Returned mmap channel areas
- * \param offset Returned mmap area offset in area steps (== frames)
+ * \param offset mmap area offset in area steps (== frames) (wanted on entry (see note), returned on exit)
* \param frames mmap area portion size in frames (wanted on entry, contiguous available on exit)
* \return 0 on success otherwise a negative error code
*
*
* See the snd_pcm_mmap_commit() function to finish the frame processing in
* the direct areas.
+ *
+ * Note: The offset value is always overriden when stop_threshold < boundary.
+ * Otherwise, the application must specify it's own offset value.
*
*/
int snd_pcm_mmap_begin(snd_pcm_t *pcm,
snd_pcm_uframes_t avail;
assert(pcm && areas && offset && frames);
*areas = snd_pcm_mmap_areas(pcm);
- *offset = *pcm->appl.ptr % pcm->buffer_size;
+ if (pcm->stop_threshold < pcm->boundary) {
+ *offset = *pcm->appl.ptr % pcm->buffer_size;
+ avail = snd_pcm_mmap_avail(pcm);
+ if (avail > pcm->buffer_size)
+ avail = pcm->buffer_size;
+ } else {
+ if (*offset >= pcm->buffer_size)
+ return -EINVAL;
+ avail = pcm->buffer_size;
+ }
cont = pcm->buffer_size - *offset;
f = *frames;
- avail = snd_pcm_mmap_avail(pcm);
- if (avail > pcm->buffer_size)
- avail = pcm->buffer_size;
if (f > avail)
f = avail;
if (f > cont)
snd_pcm_dmix_t *dmix = pcm->private_data;
int err;
- assert(pcm && delayp);
switch(dmix->state) {
case SNDRV_PCM_STATE_DRAINING:
case SNDRV_PCM_STATE_RUNNING:
}
}
+static int snd_pcm_dmix_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr)
+{
+ snd_pcm_dmix_t *dmix = pcm->private_data;
+
+ switch(dmix->state) {
+ case SNDRV_PCM_STATE_DRAINING:
+ case SNDRV_PCM_STATE_RUNNING:
+ case SNDRV_PCM_STATE_PREPARED:
+ case SNDRV_PCM_STATE_PAUSED:
+ case SNDRV_PCM_STATE_SUSPENDED:
+ *hwptr = *pcm->hw.ptr;
+ return 0;
+ case SNDRV_PCM_STATE_XRUN:
+ return -EPIPE;
+ default:
+ return -EBADFD;
+ }
+}
+
static int snd_pcm_dmix_prepare(snd_pcm_t *pcm)
{
snd_pcm_dmix_t *dmix = pcm->private_data;
status: snd_pcm_dmix_status,
state: snd_pcm_dmix_state,
hwsync: snd_pcm_dmix_hwsync,
+ hwptr: snd_pcm_dmix_hwptr,
delay: snd_pcm_dmix_delay,
prepare: snd_pcm_dmix_prepare,
reset: snd_pcm_dmix_reset,
return snd_pcm_hwsync(file->slave);
}
+static int snd_pcm_file_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr)
+{
+ snd_pcm_file_t *file = pcm->private_data;
+ return INTERNAL(snd_pcm_hwptr)(file->slave, hwptr);
+}
+
static int snd_pcm_file_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{
snd_pcm_file_t *file = pcm->private_data;
static int snd_pcm_file_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
{
snd_pcm_file_t *file = pcm->private_data;
+ /* we don't support mode without xrun detection */
+ if (params->stop_threshold >= params->boundary)
+ return -EINVAL;
return snd_pcm_sw_params(file->slave, params);
}
status: snd_pcm_file_status,
state: snd_pcm_file_state,
hwsync: snd_pcm_file_hwsync,
+ hwptr: snd_pcm_file_hwptr,
delay: snd_pcm_file_delay,
prepare: snd_pcm_file_prepare,
reset: snd_pcm_file_reset,
return snd_pcm_hwsync(h->slave);
}
+static int snd_pcm_hooks_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr)
+{
+ snd_pcm_hooks_t *h = pcm->private_data;
+ return INTERNAL(snd_pcm_hwptr)(h->slave, hwptr);
+}
+
static int snd_pcm_hooks_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{
snd_pcm_hooks_t *h = pcm->private_data;
status: snd_pcm_hooks_status,
state: snd_pcm_hooks_state,
hwsync: snd_pcm_hooks_hwsync,
+ hwptr: snd_pcm_hooks_hwptr,
delay: snd_pcm_hooks_delay,
prepare: snd_pcm_hooks_prepare,
reset: snd_pcm_hooks_reset,
hw->mmap_control->avail_min = params->avail_min;
return 0;
}
+ /* FIXME */
+ if (hw->mmap_shm && params->stop_threshold >= params->boundary)
+ return -EINVAL;
if (ioctl(fd, SNDRV_PCM_IOCTL_SW_PARAMS, params) < 0) {
SYSERR("SNDRV_PCM_IOCTL_SW_PARAMS failed");
return -errno;
return 0;
}
+static int snd_pcm_hw_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr)
+{
+ switch (snd_pcm_state(pcm)) {
+ case SND_PCM_STATE_RUNNING:
+ case SND_PCM_STATE_DRAINING:
+ case SND_PCM_STATE_PREPARED:
+ case SND_PCM_STATE_PAUSED:
+ case SND_PCM_STATE_SUSPENDED:
+ *hwptr = *pcm->hw.ptr;
+ return 0;
+ case SND_PCM_STATE_XRUN:
+ return -EPIPE;
+ default:
+ return -EBADFD;
+ }
+}
+
static int snd_pcm_hw_prepare(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private_data;
}
static snd_pcm_sframes_t snd_pcm_hw_mmap_commit(snd_pcm_t *pcm,
- snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
+ snd_pcm_uframes_t offset,
snd_pcm_uframes_t size)
{
snd_pcm_hw_t *hw = pcm->private_data;
if (hw->mmap_shm) {
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
snd_pcm_sframes_t result = 0, res;
+ snd_pcm_uframes_t last_offset;
+
+ /* FIXME */
+ last_offset = *pcm->appl.ptr - offset;
+ if (last_offset != offset)
+ return -EINVAL;
do {
res = snd_pcm_write_mmap(pcm, size);
status: snd_pcm_hw_status,
state: snd_pcm_hw_state,
hwsync: snd_pcm_hw_hwsync,
+ hwptr: snd_pcm_hw_hwptr,
delay: snd_pcm_hw_delay,
prepare: snd_pcm_hw_prepare,
reset: snd_pcm_hw_reset,
return 0;
}
+static int snd_pcm_jack_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr)
+{
+#ifdef PCM_JACK_DEBUG
+ printf("snd_pcm_jack_hwptr\n"); fflush(stdout);
+#endif
+ switch (snd_pcm_state(pcm)) {
+ case SND_PCM_STATE_RUNNING:
+ case SND_PCM_STATE_DRAINING:
+ case SND_PCM_STATE_PREPARED:
+ case SND_PCM_STATE_PAUSED:
+ case SND_PCM_STATE_SUSPENDED:
+ *hwptr = *pcm->hw.ptr;
+ return 0;
+ default:
+ return -EBADFD;
+ }
+}
+
static int snd_pcm_jack_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t *delayp)
{
#ifdef PCM_JACK_DEBUG
status: snd_pcm_jack_status,
state: snd_pcm_jack_state,
hwsync: snd_pcm_jack_hwsync,
+ hwptr: snd_pcm_jack_hwptr,
delay: snd_pcm_jack_delay,
prepare: snd_pcm_jack_prepare,
reset: snd_pcm_jack_reset,
int (*pause)(snd_pcm_t *pcm, int enable);
snd_pcm_state_t (*state)(snd_pcm_t *pcm);
int (*hwsync)(snd_pcm_t *pcm);
+ int (*hwptr)(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr);
int (*delay)(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp);
int (*resume)(snd_pcm_t *pcm);
snd_pcm_sframes_t (*rewind)(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
unsigned int *val, int *dir);
#ifdef INTERNAL
+int INTERNAL(snd_pcm_hwptr)(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr);
+
int INTERNAL(snd_pcm_hw_params_get_access)(const snd_pcm_hw_params_t *params, snd_pcm_access_t *access);
int snd_pcm_hw_params_test_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access);
int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access);
return snd_pcm_hwsync(meter->slave);
}
+static int snd_pcm_meter_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr)
+{
+ snd_pcm_meter_t *meter = pcm->private_data;
+ return INTERNAL(snd_pcm_hwptr)(meter->slave, hwptr);
+}
+
static int snd_pcm_meter_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{
snd_pcm_meter_t *meter = pcm->private_data;
static int snd_pcm_multi_async(snd_pcm_t *pcm, int sig, pid_t pid)
{
snd_pcm_multi_t *multi = pcm->private_data;
- snd_pcm_t *slave_0 = multi->slaves[0].pcm;
+ snd_pcm_t *slave_0 = multi->slaves[multi->master_slave].pcm;
return snd_pcm_async(slave_0, sig, pid);
}
static int snd_pcm_multi_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
{
snd_pcm_multi_t *multi = pcm->private_data;
- snd_pcm_t *slave = multi->slaves[0].pcm;
+ snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
return snd_pcm_status(slave, status);
}
static snd_pcm_state_t snd_pcm_multi_state(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private_data;
- snd_pcm_t *slave = multi->slaves[0].pcm;
+ snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
return snd_pcm_state(slave);
}
static int snd_pcm_multi_hwsync(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private_data;
- snd_pcm_t *slave = multi->slaves[0].pcm;
+ snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
return snd_pcm_hwsync(slave);
}
+static int snd_pcm_multi_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr)
+{
+ snd_pcm_multi_t *multi = pcm->private_data;
+ snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
+ return INTERNAL(snd_pcm_hwptr)(slave, hwptr);
+}
+
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_t *slave = multi->slaves[0].pcm;
+ snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
return snd_pcm_delay(slave, delayp);
}
status: snd_pcm_multi_status,
state: snd_pcm_multi_state,
hwsync: snd_pcm_multi_hwsync,
+ hwptr: snd_pcm_multi_hwptr,
delay: snd_pcm_multi_delay,
prepare: snd_pcm_multi_prepare,
reset: snd_pcm_multi_reset,
return 0;
}
+static int snd_pcm_null_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr)
+{
+ switch (snd_pcm_state(pcm)) {
+ case SND_PCM_STATE_RUNNING:
+ case SND_PCM_STATE_DRAINING:
+ case SND_PCM_STATE_PREPARED:
+ case SND_PCM_STATE_PAUSED:
+ case SND_PCM_STATE_SUSPENDED:
+ *hwptr = *pcm->hw.ptr;
+ return 0;
+ case SND_PCM_STATE_XRUN:
+ return -EPIPE;
+ default:
+ return -EBADFD;
+ }
+}
+
static int snd_pcm_null_delay(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sframes_t *delayp)
{
*delayp = 0;
status: snd_pcm_null_status,
state: snd_pcm_null_state,
hwsync: snd_pcm_null_hwsync,
+ hwptr: snd_pcm_null_hwptr,
delay: snd_pcm_null_delay,
prepare: snd_pcm_null_prepare,
reset: snd_pcm_null_reset,
return snd_pcm_hwsync(plugin->slave);
}
+int snd_pcm_plugin_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr)
+{
+ snd_pcm_plugin_t *plugin = pcm->private_data;
+ return INTERNAL(snd_pcm_hwptr)(plugin->slave, hwptr);
+}
+
int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{
snd_pcm_plugin_t *plugin = pcm->private_data;
status: snd_pcm_plugin_status,
state: snd_pcm_plugin_state,
hwsync: snd_pcm_plugin_hwsync,
+ hwptr: snd_pcm_plugin_hwptr,
delay: snd_pcm_plugin_delay,
prepare: snd_pcm_plugin_prepare,
reset: snd_pcm_plugin_reset,
return err;
}
+static int _snd_pcm_share_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr)
+{
+ snd_pcm_share_t *share = pcm->private_data;
+ snd_pcm_share_slave_t *slave = share->slave;
+ switch (share->state) {
+ case SND_PCM_STATE_RUNNING:
+ case SND_PCM_STATE_DRAINING:
+ case SND_PCM_STATE_PREPARED:
+ case SND_PCM_STATE_PAUSED:
+ case SND_PCM_STATE_SUSPENDED:
+ *hwptr = *pcm->hw.ptr;
+ return 0;
+ case SND_PCM_STATE_XRUN:
+ return -EPIPE;
+ default:
+ return -EBADFD;
+ }
+}
+
+static int snd_pcm_share_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *hwptr)
+{
+ 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_hwptr(pcm, hwptr);
+ Pthread_mutex_unlock(&slave->mutex);
+ return err;
+}
+
static int _snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{
snd_pcm_share_t *share = pcm->private_data;
status: snd_pcm_share_status,
state: snd_pcm_share_state,
hwsync: snd_pcm_share_hwsync,
+ hwptr: snd_pcm_share_hwptr,
delay: snd_pcm_share_delay,
prepare: snd_pcm_share_prepare,
reset: snd_pcm_share_reset,
return snd_pcm_shm_action(pcm);
}
+static int snd_pcm_shm_hwptr(snd_pcm_t *pcm, snd_pcm_uframes_t *uframes)
+{
+ snd_pcm_shm_t *shm = pcm->private_data;
+ volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
+ int err;
+ ctrl->cmd = SND_PCM_IOCTL_HWPTR;
+ return snd_pcm_shm_action(pcm);
+ if (err < 0)
+ return err;
+ *uframes = ctrl->u.hwptr.frames;
+ return err;
+}
+
static int snd_pcm_shm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{
snd_pcm_shm_t *shm = pcm->private_data;
status: snd_pcm_shm_status,
state: snd_pcm_shm_state,
hwsync: snd_pcm_shm_hwsync,
+ hwptr: snd_pcm_shm_hwptr,
delay: snd_pcm_shm_delay,
prepare: snd_pcm_shm_prepare,
reset: snd_pcm_shm_reset,