ctrl->result = snd_pcm_munmap(pcm);
break;
}
- case SND_PCM_IOCTL_MMAP_FORWARD:
- ctrl->result = snd_pcm_mmap_forward(pcm, ctrl->u.mmap_forward.frames);
+ case SND_PCM_IOCTL_MMAP_COMMIT:
+ ctrl->result = snd_pcm_mmap_commit(pcm,
+ ctrl->u.mmap_commit.offset,
+ ctrl->u.mmap_commit.frames);
ctrl->appl_ptr = *pcm->appl_ptr;
break;
case SND_PCM_IOCTL_POLL_DESCRIPTOR:
ctrl->result = snd_ctl_pcm_next_device(ctl, &ctrl->u.device);
break;
case SND_CTL_IOCTL_PCM_SURROUND_NEXT_DEVICE:
- ctrl->result = snd_ctl_pcm_surround_next_device(ctl, &ctrl->u.surround.type, &ctrl->u.surround.device);
+ ctrl->result = snd_ctl_pcm_surround_next_device(ctl, ctrl->u.surround.type, &ctrl->u.surround.device);
break;
case SNDRV_CTL_IOCTL_PCM_INFO:
ctrl->result = snd_ctl_pcm_info(ctl, &ctrl->u.pcm_info);
#define SND_PCM_IOCTL_STATE _IO ('A', 0xf1)
#define SND_PCM_IOCTL_MMAP _IO ('A', 0xf2)
#define SND_PCM_IOCTL_MUNMAP _IO ('A', 0xf3)
-#define SND_PCM_IOCTL_MMAP_FORWARD _IO ('A', 0xf4)
+#define SND_PCM_IOCTL_MMAP_COMMIT _IO ('A', 0xf4)
#define SND_PCM_IOCTL_AVAIL_UPDATE _IO ('A', 0xf5)
#define SND_PCM_IOCTL_ASYNC _IO ('A', 0xf6)
#define SND_PCM_IOCTL_CLOSE _IO ('A', 0xf7)
int fd;
} link;
struct {
+ snd_pcm_uframes_t offset;
snd_pcm_uframes_t frames;
- } mmap_forward;
+ } mmap_commit;
} u;
char data[0];
} snd_pcm_shm_ctrl_t;
} async;
int device;
struct {
- int type;
+ snd_pcm_surround_type_t type;
int device;
} surround;
int subscribe_events;
int snd_pcm_status_dump(snd_pcm_status_t *status, snd_output_t *out);
/* mmap */
-const snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm);
-const snd_pcm_channel_area_t *snd_pcm_mmap_running_areas(snd_pcm_t *pcm);
-const snd_pcm_channel_area_t *snd_pcm_mmap_stopped_areas(snd_pcm_t *pcm);
-snd_pcm_sframes_t snd_pcm_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size);
-snd_pcm_uframes_t snd_pcm_mmap_offset(snd_pcm_t *pcm);
-snd_pcm_uframes_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, snd_pcm_uframes_t size);
-snd_pcm_sframes_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size);
-snd_pcm_sframes_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size);
-snd_pcm_sframes_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size);
-snd_pcm_sframes_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size);
+int snd_pcm_mmap_begin(snd_pcm_t *pcm,
+ const snd_pcm_channel_area_t **areas,
+ snd_pcm_uframes_t *offset,
+ snd_pcm_uframes_t *frames);
+int snd_pcm_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t frames);
const char *snd_pcm_stream_name(snd_pcm_stream_t stream);
const char *snd_pcm_access_name(snd_pcm_access_t _access);
return pcm->fast_ops->avail_update(pcm->fast_op_arg);
}
-/**
- * \brief Advance PCM frame position in mmap buffer
- * \param pcm PCM handle
- * \param size movement size
- * \return a positive number of actual movement size otherwise a negative
- * error code
- *
- * On playback does all the actions needed to transport the frames across
- * underlying layers.
- */
-snd_pcm_sframes_t snd_pcm_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size)
-{
- assert(size > 0);
- assert(size <= snd_pcm_mmap_avail(pcm));
- return pcm->fast_ops->mmap_forward(pcm->fast_op_arg, size);
-}
-
/**
* \brief Silence an area
* \param dst_area area specification
obj->stream = snd_enum_to_int(val);
}
-
-/**
- * \brief Get channel areas for a given PCM when running
- * \param pcm PCM handle
- * \return pointer to channel areas (one for each channel)
- */
-const snd_pcm_channel_area_t *snd_pcm_mmap_running_areas(snd_pcm_t *pcm)
-{
- return pcm->running_areas;
-}
-
-/**
- * \brief Get channel areas for a given PCM when stopped
- * \param pcm PCM handle
- * \return pointer to channel areas (one for each channel)
- */
-const snd_pcm_channel_area_t *snd_pcm_mmap_stopped_areas(snd_pcm_t *pcm)
-{
- return pcm->stopped_areas;
-}
-
/**
- * \brief Get appropriate channel areas for a given PCM according to its state (running or stopped)
+ * \brief Application request to access a portion of mmap area
* \param pcm PCM handle
- * \return pointer to channel areas (one for each channel)
+ * \param areas Returned mmap channel areas
+ * \param offset Returned mmap area offset
+ * \param size mmap area portion size (wanted on entry, contiguous
+available on exit)
+ * \return 0 on success otherwise a negative error code
*/
-const snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm)
+int snd_pcm_mmap_begin(snd_pcm_t *pcm,
+ const snd_pcm_channel_area_t **areas,
+ snd_pcm_uframes_t *offset,
+ snd_pcm_uframes_t *frames)
{
+ snd_pcm_uframes_t cont;
+ snd_pcm_uframes_t avail;
+ snd_pcm_uframes_t f;
+ assert(pcm && areas && offset && frames);
if (pcm->stopped_areas &&
snd_pcm_state(pcm) != SND_PCM_STATE_RUNNING)
- return pcm->stopped_areas;
- return pcm->running_areas;
-}
-
-/**
- * \brief Correct frames count according to contiguity consideration inside PCM ring buffer
- * \param pcm PCM handle
- * \param frames Frames to transfer
- * \return Number of contiguous frames transferrable
- */
-snd_pcm_uframes_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
-{
- assert(pcm);
- if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
- return snd_pcm_mmap_playback_xfer(pcm, frames);
+ *areas = pcm->stopped_areas;
else
- return snd_pcm_mmap_capture_xfer(pcm, frames);
+ *areas = pcm->running_areas;
+ *offset = *pcm->appl_ptr % pcm->buffer_size;
+ avail = snd_pcm_mmap_avail(pcm);
+ f = *frames;
+ if (f > avail)
+ f = avail;
+ cont = pcm->buffer_size - *pcm->appl_ptr % pcm->buffer_size;
+ if (f > cont)
+ f = cont;
+ *frames = f;
+ return 0;
}
/**
- * \brief Return application offset inside ring buffer
+ * \brief Application has completed the access to area requested with
+#snd_pcm_mmap_begin
* \param pcm PCM handle
- * \return Offset for frames transfer
+ * \return 0 on success otherwise a negative error code
+ *
+ * To call this with offset/frames values different from that returned
+ * by snd_pcm_mmap_begin has undefined effects and it has to be avoided.
*/
-snd_pcm_uframes_t snd_pcm_mmap_offset(snd_pcm_t *pcm)
+int snd_pcm_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t frames)
{
- assert(pcm);
- return *pcm->appl_ptr % pcm->buffer_size;
+ assert(pcm);
+ assert(offset == *pcm->appl_ptr % pcm->buffer_size);
+ assert(frames <= snd_pcm_mmap_avail(pcm));
+ return pcm->fast_ops->mmap_commit(pcm->fast_op_arg, offset, frames);
}
#ifndef DOC_HIDDEN
return n;
}
-static snd_pcm_sframes_t snd_pcm_file_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size)
+static snd_pcm_sframes_t snd_pcm_file_mmap_commit(snd_pcm_t *pcm,
+ snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t size)
{
snd_pcm_file_t *file = pcm->private_data;
- snd_pcm_uframes_t ofs = snd_pcm_mmap_offset(pcm);
- snd_pcm_sframes_t n = snd_pcm_mmap_forward(file->slave, size);
- snd_pcm_uframes_t xfer = 0;
- if (n <= 0)
- return n;
- while (xfer < (snd_pcm_uframes_t)n) {
- snd_pcm_uframes_t frames = n - xfer;
- snd_pcm_uframes_t cont = pcm->buffer_size - ofs;
- if (frames > cont)
- frames = cont;
- snd_pcm_file_add_frames(pcm, snd_pcm_mmap_areas(file->slave), ofs, frames);
- ofs += frames;
- if (ofs == pcm->buffer_size)
- ofs = 0;
- xfer += frames;
- }
- return n;
+ snd_pcm_uframes_t ofs;
+ snd_pcm_uframes_t siz = size;
+ const snd_pcm_channel_area_t *areas;
+ snd_pcm_mmap_begin(file->slave, &areas, &ofs, &siz);
+ assert(ofs == offset && siz == size);
+ snd_pcm_mmap_commit(file->slave, ofs, siz);
+ snd_pcm_file_add_frames(pcm, areas, ofs, siz);
+ return 0;
}
static snd_pcm_sframes_t snd_pcm_file_avail_update(snd_pcm_t *pcm)
readi: snd_pcm_file_readi,
readn: snd_pcm_file_readn,
avail_update: snd_pcm_file_avail_update,
- mmap_forward: snd_pcm_file_mmap_forward,
+ mmap_commit: snd_pcm_file_mmap_commit,
};
int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, const char *fname, int fd, const char *fmt, snd_pcm_t *slave, int close_slave)
return 0;
}
-static snd_pcm_sframes_t snd_pcm_hw_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size)
+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 size)
{
if (!(pcm->info & SND_PCM_INFO_MMAP) &&
pcm->stream == SND_PCM_STREAM_PLAYBACK)
readi: snd_pcm_hw_readi,
readn: snd_pcm_hw_readn,
avail_update: snd_pcm_hw_avail_update,
- mmap_forward: snd_pcm_hw_mmap_forward,
+ mmap_commit: snd_pcm_hw_mmap_commit,
};
static int snd_pcm_hw_open_subdevice(snd_pcm_t **pcmp, int card, int device, int subdevice, snd_pcm_stream_t stream, int mode)
snd_pcm_sframes_t (*readi)(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size);
snd_pcm_sframes_t (*readn)(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size);
snd_pcm_sframes_t (*avail_update)(snd_pcm_t *pcm);
- snd_pcm_sframes_t (*mmap_forward)(snd_pcm_t *pcm, snd_pcm_uframes_t size);
+ snd_pcm_sframes_t (*mmap_commit)(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size);
} snd_pcm_fast_ops_t;
struct _snd_pcm {
void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
void snd_pcm_mmap_hw_backward(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
-snd_pcm_uframes_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm);
-snd_pcm_uframes_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
-snd_pcm_uframes_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, snd_pcm_uframes_t frames);
+
+snd_pcm_sframes_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size);
+snd_pcm_sframes_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size);
+snd_pcm_sframes_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size);
+snd_pcm_sframes_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size);
typedef snd_pcm_uframes_t (*snd_pcm_xfer_areas_func_t)(snd_pcm_t *pcm,
const snd_pcm_channel_area_t *areas,
return pcm->buffer_size - avail;
}
+static inline const snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm)
+{
+ if (pcm->stopped_areas &&
+ snd_pcm_state(pcm) != SND_PCM_STATE_RUNNING)
+ return pcm->stopped_areas;
+ return pcm->running_areas;
+}
+
+static inline snd_pcm_uframes_t snd_pcm_mmap_offset(snd_pcm_t *pcm)
+{
+ assert(pcm);
+ return *pcm->appl_ptr % pcm->buffer_size;
+}
+
+static inline snd_pcm_uframes_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm)
+{
+ assert(pcm);
+ return *pcm->hw_ptr % pcm->buffer_size;
+}
+
#define snd_pcm_mmap_playback_delay snd_pcm_mmap_playback_hw_avail
#define snd_pcm_mmap_capture_delay snd_pcm_mmap_capture_avail
return err;
}
-static snd_pcm_sframes_t snd_pcm_meter_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size)
+static snd_pcm_sframes_t snd_pcm_meter_mmap_commit(snd_pcm_t *pcm,
+ snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t size)
{
snd_pcm_meter_t *meter = pcm->private_data;
snd_pcm_uframes_t old_rptr = *pcm->appl_ptr;
- snd_pcm_sframes_t result = snd_pcm_mmap_forward(meter->slave, size);
+ snd_pcm_sframes_t result = snd_pcm_mmap_commit(meter->slave, offset, size);
if (result <= 0)
return result;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
readi: snd_pcm_mmap_readi,
readn: snd_pcm_mmap_readn,
avail_update: snd_pcm_meter_avail_update,
- mmap_forward: snd_pcm_meter_mmap_forward,
+ mmap_commit: snd_pcm_meter_mmap_commit,
};
int snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, unsigned int frequency,
return size;
}
-snd_pcm_uframes_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
-{
- snd_pcm_uframes_t cont;
- snd_pcm_uframes_t avail = snd_pcm_mmap_playback_avail(pcm);
- if (avail < frames)
- frames = avail;
- cont = pcm->buffer_size - *pcm->appl_ptr % pcm->buffer_size;
- if (cont < frames)
- frames = cont;
- return frames;
-}
-
-snd_pcm_uframes_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
-{
- snd_pcm_uframes_t cont;
- snd_pcm_uframes_t avail = snd_pcm_mmap_capture_avail(pcm);
- if (avail < frames)
- frames = avail;
- cont = pcm->buffer_size - *pcm->appl_ptr % pcm->buffer_size;
- if (cont < frames)
- frames = cont;
- return frames;
-}
-
-snd_pcm_uframes_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm)
-{
- assert(pcm);
- return *pcm->hw_ptr % pcm->buffer_size;
-}
-
void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
{
snd_pcm_sframes_t appl_ptr = *pcm->appl_ptr;
snd_pcm_uframes_t offset,
snd_pcm_uframes_t size)
{
- const snd_pcm_channel_area_t *pcm_areas;
- snd_pcm_uframes_t pcm_offset;
snd_pcm_uframes_t xfer = size;
assert(snd_pcm_mmap_playback_avail(pcm) >= size);
- pcm_areas = snd_pcm_mmap_areas(pcm);
- pcm_offset = snd_pcm_mmap_offset(pcm);
while (size > 0) {
+ const snd_pcm_channel_area_t *pcm_areas;
+ snd_pcm_uframes_t pcm_offset;
snd_pcm_uframes_t frames = size;
- snd_pcm_uframes_t cont = pcm->buffer_size - pcm_offset;
- int err;
- if (frames > cont)
- frames = cont;
+ snd_pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames);
snd_pcm_areas_copy(pcm_areas, pcm_offset,
areas, offset,
pcm->channels,
frames, pcm->format);
- err = snd_pcm_mmap_forward(pcm, frames);
- assert(err == (snd_pcm_sframes_t)frames);
- if (frames == cont)
- pcm_offset = 0;
- else
- pcm_offset += frames;
+ snd_pcm_mmap_commit(pcm, pcm_offset, frames);
offset += frames;
size -= frames;
}
snd_pcm_uframes_t offset,
snd_pcm_uframes_t size)
{
- const snd_pcm_channel_area_t *pcm_areas;
- snd_pcm_uframes_t pcm_offset;
snd_pcm_uframes_t xfer = size;
assert(snd_pcm_mmap_capture_avail(pcm) >= size);
- pcm_areas = snd_pcm_mmap_areas(pcm);
- pcm_offset = snd_pcm_mmap_offset(pcm);
while (size > 0) {
+ const snd_pcm_channel_area_t *pcm_areas;
+ snd_pcm_uframes_t pcm_offset;
snd_pcm_uframes_t frames = size;
- snd_pcm_uframes_t cont = pcm->buffer_size - pcm_offset;
- int err;
- if (frames > cont)
- frames = cont;
+ snd_pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames);
snd_pcm_areas_copy(areas, offset,
pcm_areas, pcm_offset,
pcm->channels,
frames, pcm->format);
- err = snd_pcm_mmap_forward(pcm, frames);
- assert(err == (snd_pcm_sframes_t)frames);
- if (frames == cont)
- pcm_offset = 0;
- else
- pcm_offset += frames;
+ snd_pcm_mmap_commit(pcm, pcm_offset, frames);
offset += frames;
size -= frames;
}
snd_pcm_t *pcm;
unsigned int channels_count;
int close_slave;
+ int linked;
} snd_pcm_multi_slave_t;
typedef struct {
unsigned int i;
int ret = 0;
for (i = 0; i < multi->slaves_count; ++i) {
- int err;
snd_pcm_multi_slave_t *slave = &multi->slaves[i];
- if (slave->close_slave)
- err = snd_pcm_close(slave->pcm);
- else
- err = snd_pcm_unlink(slave->pcm);
- if (err < 0)
- ret = err;
+ if (slave->close_slave) {
+ int err = snd_pcm_close(slave->pcm);
+ if (err < 0)
+ ret = err;
+ }
}
free(multi->slaves);
free(multi->channels);
{
snd_pcm_multi_t *multi = pcm->private_data;
snd_pcm_t *slave = multi->slaves[slave_idx].pcm;
- int err = snd_pcm_hw_refine(slave, sparams);
+ int err = snd_pcm_hw_params(slave, sparams);
if (err < 0)
return err;
err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format);
static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_multi_t *multi = pcm->private_data;
- unsigned int k;
+ unsigned int i;
snd_pcm_hw_params_t sparams[multi->slaves_count];
int err;
- for (k = 0; k < multi->slaves_count; ++k) {
- err = snd_pcm_multi_hw_refine_sprepare(pcm, k, &sparams[k]);
+ for (i = 0; i < multi->slaves_count; ++i) {
+ err = snd_pcm_multi_hw_refine_sprepare(pcm, i, &sparams[i]);
assert(err >= 0);
- err = snd_pcm_multi_hw_refine_schange(pcm, k, params, &sparams[k]);
+ err = snd_pcm_multi_hw_refine_schange(pcm, i, params, &sparams[i]);
assert(err >= 0);
- err = snd_pcm_multi_hw_params_slave(pcm, k, &sparams[k]);
+ err = snd_pcm_multi_hw_params_slave(pcm, i, &sparams[i]);
if (err < 0) {
- snd_pcm_multi_hw_refine_cchange(pcm, k, params, &sparams[k]);
+ snd_pcm_multi_hw_refine_cchange(pcm, i, params, &sparams[i]);
return err;
}
}
+ multi->slaves[0].linked = 0;
+ for (i = 1; i < multi->slaves_count; ++i) {
+ err = snd_pcm_link(multi->slaves[0].pcm, multi->slaves[i].pcm);
+ multi->slaves[i].linked = (err >= 0);
+ }
return 0;
}
int e = snd_pcm_hw_free(slave);
if (e < 0)
err = e;
+ if (!multi->slaves[i].linked)
+ continue;
+ e = snd_pcm_unlink(slave);
+ if (e < 0)
+ err = e;
}
return err;
}
static snd_pcm_sframes_t snd_pcm_multi_avail_update(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private_data;
- snd_pcm_t *slave = multi->slaves[0].pcm;
- return snd_pcm_avail_update(slave);
+ snd_pcm_sframes_t ret = LONG_MAX;
+ unsigned int i;
+ for (i = 0; i < multi->slaves_count; ++i) {
+ snd_pcm_sframes_t avail;
+ avail = snd_pcm_avail_update(multi->slaves[i].pcm);
+ if (avail < 0)
+ return avail;
+ if (ret > avail)
+ ret = avail;
+ }
+ return ret;
}
static int snd_pcm_multi_prepare(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private_data;
- return snd_pcm_prepare(multi->slaves[0].pcm);
+ int err = 0;
+ unsigned int i;
+ for (i = 0; i < multi->slaves_count; ++i) {
+ if (multi->slaves[i].linked)
+ continue;
+ err = snd_pcm_prepare(multi->slaves[i].pcm);
+ if (err < 0)
+ return err;
+ }
+ return err;
}
static int snd_pcm_multi_reset(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private_data;
- return snd_pcm_reset(multi->slaves[0].pcm);
+ int err = 0;
+ unsigned int i;
+ for (i = 0; i < multi->slaves_count; ++i) {
+ if (multi->slaves[i].linked)
+ continue;
+ err = snd_pcm_reset(multi->slaves[i].pcm);
+ if (err < 0)
+ return err;
+ }
+ return err;
}
static int snd_pcm_multi_start(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private_data;
- return snd_pcm_start(multi->slaves[0].pcm);
+ int err = 0;
+ unsigned int i;
+ for (i = 0; i < multi->slaves_count; ++i) {
+ if (multi->slaves[i].linked)
+ continue;
+ err = snd_pcm_start(multi->slaves[i].pcm);
+ if (err < 0)
+ return err;
+ }
+ return err;
}
static int snd_pcm_multi_drop(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private_data;
- return snd_pcm_drop(multi->slaves[0].pcm);
+ int err = 0;
+ unsigned int i;
+ for (i = 0; i < multi->slaves_count; ++i) {
+ if (multi->slaves[i].linked)
+ continue;
+ err = snd_pcm_drop(multi->slaves[i].pcm);
+ if (err < 0)
+ return err;
+ }
+ return err;
}
static int snd_pcm_multi_drain(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private_data;
- return snd_pcm_drain(multi->slaves[0].pcm);
+ int err = 0;
+ unsigned int i;
+ for (i = 0; i < multi->slaves_count; ++i) {
+ if (multi->slaves[i].linked)
+ continue;
+ err = snd_pcm_drain(multi->slaves[i].pcm);
+ if (err < 0)
+ return err;
+ }
+ return err;
}
static int snd_pcm_multi_pause(snd_pcm_t *pcm, int enable)
{
snd_pcm_multi_t *multi = pcm->private_data;
- return snd_pcm_pause(multi->slaves[0].pcm, enable);
+ int err = 0;
+ unsigned int i;
+ for (i = 0; i < multi->slaves_count; ++i) {
+ if (multi->slaves[i].linked)
+ continue;
+ err = snd_pcm_pause(multi->slaves[i].pcm, enable);
+ if (err < 0)
+ return err;
+ }
+ return err;
}
static int snd_pcm_multi_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
snd_pcm_t *slave_i = multi->slaves[i].pcm;
snd_pcm_uframes_t f = pos[i] - frames;
if (f > 0)
- snd_pcm_mmap_forward(slave_i, f);
+ snd_pcm_mmap_commit(slave_i, snd_pcm_mmap_offset(slave_i), f);
}
return frames;
}
-static snd_pcm_sframes_t snd_pcm_multi_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size)
+static snd_pcm_sframes_t snd_pcm_multi_mmap_commit(snd_pcm_t *pcm,
+ snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t size)
{
snd_pcm_multi_t *multi = pcm->private_data;
unsigned int i;
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *slave = multi->slaves[i].pcm;
- snd_pcm_sframes_t frames = snd_pcm_mmap_forward(slave, size);
+ snd_pcm_sframes_t frames = snd_pcm_mmap_commit(slave, offset, size);
if (frames < 0)
return frames;
if (i == 0) {
readn: snd_pcm_mmap_readn,
rewind: snd_pcm_multi_rewind,
avail_update: snd_pcm_multi_avail_update,
- mmap_forward: snd_pcm_multi_mmap_forward,
+ mmap_commit: snd_pcm_multi_mmap_commit,
};
int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name,
slave->pcm = slaves_pcm[i];
slave->channels_count = schannels_count[i];
slave->close_slave = close_slaves;
- if (i != 0)
- snd_pcm_link(slaves_pcm[i-1], slaves_pcm[i]);
}
for (i = 0; i < channels_count; ++i) {
snd_pcm_multi_channel_t *bind = &multi->channels[i];
return snd_pcm_null_fwd(pcm, size);
}
-static snd_pcm_sframes_t snd_pcm_null_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size)
+static snd_pcm_sframes_t snd_pcm_null_mmap_commit(snd_pcm_t *pcm,
+ snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
+ snd_pcm_uframes_t size)
{
return snd_pcm_null_fwd(pcm, size);
}
readi: snd_pcm_null_readi,
readn: snd_pcm_null_readn,
avail_update: snd_pcm_null_avail_update,
- mmap_forward: snd_pcm_null_mmap_forward,
+ mmap_commit: snd_pcm_null_mmap_commit,
};
int snd_pcm_null_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode)
{
snd_pcm_plugin_t *plugin = pcm->private_data;
snd_pcm_t *slave = plugin->slave;
- const snd_pcm_channel_area_t *slave_areas;
- snd_pcm_uframes_t slave_offset;
snd_pcm_uframes_t xfer = size;
- slave_areas = snd_pcm_mmap_areas(slave);
- slave_offset = snd_pcm_mmap_offset(slave);
while (size > 0) {
snd_pcm_uframes_t frames = size;
- snd_pcm_uframes_t slave_cont = slave->buffer_size - slave_offset;
- snd_pcm_uframes_t slave_frames = slave_cont;
+ const snd_pcm_channel_area_t *slave_areas;
+ snd_pcm_uframes_t slave_offset, slave_frames;
+ snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
frames = plugin->write(pcm, areas, offset, frames,
slave_areas, slave_offset, &slave_frames);
assert(slave_frames <= snd_pcm_mmap_playback_avail(slave));
snd_atomic_write_begin(&plugin->watom);
snd_pcm_mmap_appl_forward(pcm, frames);
snd_pcm_mmap_hw_forward(pcm, frames);
- snd_pcm_mmap_forward(slave, slave_frames);
+ snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
snd_atomic_write_end(&plugin->watom);
offset += frames;
size -= frames;
- if (slave_frames == slave_cont)
- slave_offset = 0;
- else
- slave_offset += slave_frames;
}
return xfer;
}
{
snd_pcm_plugin_t *plugin = pcm->private_data;
snd_pcm_t *slave = plugin->slave;
- const snd_pcm_channel_area_t *slave_areas;
- snd_pcm_uframes_t slave_offset;
snd_pcm_uframes_t xfer = size;
- slave_areas = snd_pcm_mmap_areas(slave);
- slave_offset = snd_pcm_mmap_offset(slave);
while (size > 0) {
snd_pcm_uframes_t frames = size;
- snd_pcm_uframes_t slave_cont = slave->buffer_size - slave_offset;
- snd_pcm_uframes_t slave_frames = slave_cont;
+ const snd_pcm_channel_area_t *slave_areas;
+ snd_pcm_uframes_t slave_offset, slave_frames;
+ snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
frames = plugin->read(pcm, areas, offset, frames,
slave_areas, slave_offset, &slave_frames);
assert(slave_frames <= snd_pcm_mmap_capture_avail(slave));
snd_atomic_write_begin(&plugin->watom);
snd_pcm_mmap_appl_forward(pcm, frames);
snd_pcm_mmap_hw_forward(pcm, frames);
- snd_pcm_mmap_forward(slave, slave_frames);
+ snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
snd_atomic_write_end(&plugin->watom);
offset += frames;
size -= frames;
- if (slave_frames == slave_cont)
- slave_offset = 0;
- else
- slave_offset += slave_frames;
}
return xfer;
}
snd_pcm_plugin_read_areas);
}
-snd_pcm_sframes_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size)
+snd_pcm_sframes_t snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm,
+ snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
+ snd_pcm_uframes_t size)
{
snd_pcm_plugin_t *plugin = pcm->private_data;
snd_pcm_t *slave = plugin->slave;
- const snd_pcm_channel_area_t *areas, *slave_areas;
- snd_pcm_uframes_t xfer, offset;
- snd_pcm_uframes_t slave_offset, slave_size;
+ const snd_pcm_channel_area_t *areas;
+ snd_pcm_uframes_t xfer, hw_offset;
+ snd_pcm_uframes_t slave_size;
if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
snd_atomic_write_begin(&plugin->watom);
snd_pcm_mmap_appl_forward(pcm, size);
if (slave_size <= 0)
return slave_size;
areas = snd_pcm_mmap_areas(pcm);
- offset = snd_pcm_mmap_hw_offset(pcm);
- slave_areas = snd_pcm_mmap_areas(slave);
- slave_offset = snd_pcm_mmap_offset(slave);
+ hw_offset = snd_pcm_mmap_hw_offset(pcm);
xfer = 0;
while (size && slave_size) {
snd_pcm_uframes_t frames = size;
- snd_pcm_uframes_t cont = pcm->buffer_size - offset;
- snd_pcm_uframes_t slave_frames = slave_size;
- snd_pcm_uframes_t slave_cont = slave->buffer_size - slave_offset;
+ snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset;
+ const snd_pcm_channel_area_t *slave_areas;
+ snd_pcm_uframes_t slave_offset, slave_frames;
+ snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
if (frames > cont)
frames = cont;
- if (slave_frames > slave_cont)
- slave_frames = slave_cont;
- frames = plugin->write(pcm, areas, offset, frames,
+ frames = plugin->write(pcm, areas, hw_offset, frames,
slave_areas, slave_offset, &slave_frames);
snd_atomic_write_begin(&plugin->watom);
snd_pcm_mmap_appl_forward(pcm, frames);
snd_pcm_mmap_hw_forward(pcm, frames);
- snd_pcm_mmap_forward(slave, slave_frames);
+ snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
snd_atomic_write_end(&plugin->watom);
xfer += frames;
if (frames == cont)
- offset = 0;
+ hw_offset = 0;
else
- offset += frames;
+ hw_offset += frames;
size -= frames;
- if (slave_frames == slave_cont)
- slave_offset = 0;
- else
- slave_offset += slave_frames;
slave_size -= slave_frames;
}
return xfer;
{
snd_pcm_plugin_t *plugin = pcm->private_data;
snd_pcm_t *slave = plugin->slave;
- const snd_pcm_channel_area_t *areas, *slave_areas;
- snd_pcm_uframes_t xfer, offset, size;
- snd_pcm_uframes_t slave_offset;
+ const snd_pcm_channel_area_t *areas;
+ snd_pcm_uframes_t xfer, hw_offset, size;
snd_pcm_sframes_t slave_size;
slave_size = snd_pcm_avail_update(slave);
if (slave_size <= 0)
xfer = snd_pcm_mmap_capture_avail(pcm);
size = pcm->buffer_size - xfer;
areas = snd_pcm_mmap_areas(pcm);
- offset = snd_pcm_mmap_hw_offset(pcm);
- slave_areas = snd_pcm_mmap_areas(slave);
- slave_offset = snd_pcm_mmap_offset(slave);
+ hw_offset = snd_pcm_mmap_hw_offset(pcm);
while (size && slave_size) {
snd_pcm_uframes_t frames = size;
- snd_pcm_uframes_t cont = pcm->buffer_size - offset;
- snd_pcm_uframes_t slave_frames = slave_size;
- snd_pcm_uframes_t slave_cont = slave->buffer_size - slave_offset;
+ snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset;
+ const snd_pcm_channel_area_t *slave_areas;
+ snd_pcm_uframes_t slave_offset, slave_frames;
+ snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
if (frames > cont)
frames = cont;
- if (slave_frames > slave_cont)
- slave_frames = slave_cont;
- frames = plugin->read(pcm, areas, offset, frames,
+ frames = plugin->read(pcm, areas, hw_offset, frames,
slave_areas, slave_offset, &slave_frames);
snd_atomic_write_begin(&plugin->watom);
snd_pcm_mmap_hw_forward(pcm, frames);
- snd_pcm_mmap_forward(slave, slave_frames);
+ snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
snd_atomic_write_end(&plugin->watom);
xfer += frames;
if (frames == cont)
- offset = 0;
+ hw_offset = 0;
else
- offset += frames;
+ hw_offset += frames;
size -= frames;
- if (slave_frames == slave_cont)
- slave_offset = 0;
- else
- slave_offset += slave_frames;
slave_size -= slave_frames;
}
return xfer;
readi: snd_pcm_plugin_readi,
readn: snd_pcm_plugin_readn,
avail_update: snd_pcm_plugin_avail_update,
- mmap_forward: snd_pcm_plugin_mmap_forward,
+ mmap_commit: snd_pcm_plugin_mmap_commit,
};
snd_pcm_sframes_t snd_pcm_plugin_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size);
snd_pcm_sframes_t snd_pcm_plugin_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size);
snd_pcm_sframes_t snd_pcm_plugin_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size);
-snd_pcm_sframes_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size);
+snd_pcm_sframes_t snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size);
snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm);
int snd_pcm_plugin_mmap_status(snd_pcm_t *pcm);
int snd_pcm_plugin_mmap_control(snd_pcm_t *pcm);
}
/* Warning: take the mutex before to call this */
-/* Return number of frames to mmap_forward the slave */
+/* Return number of frames to mmap_commit the slave */
static snd_pcm_uframes_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
{
struct list_head *i;
frames = -safety_missing;
missing = 1;
}
- err = snd_pcm_mmap_forward(spcm, frames);
+ err = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), frames);
assert(err == frames);
slave_avail -= frames;
} else {
}
/* Call it with mutex held */
-static snd_pcm_sframes_t _snd_pcm_share_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size)
+static snd_pcm_sframes_t _snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
+ snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
+ snd_pcm_uframes_t size)
{
snd_pcm_share_t *share = pcm->private_data;
snd_pcm_share_slave_t *slave = share->slave;
+ snd_pcm_t *spcm = slave->pcm;
snd_pcm_sframes_t ret = 0;
snd_pcm_sframes_t frames;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
share->state == SND_PCM_STATE_RUNNING) {
- frames = *slave->pcm->appl_ptr - share->appl_ptr;
+ frames = *spcm->appl_ptr - share->appl_ptr;
if (frames > (snd_pcm_sframes_t)pcm->buffer_size)
frames -= pcm->boundary;
else if (frames < -(snd_pcm_sframes_t)pcm->buffer_size)
frames += pcm->boundary;
if (frames > 0) {
/* Latecomer PCM */
- ret = snd_pcm_rewind(slave->pcm, frames);
+ ret = snd_pcm_rewind(spcm, frames);
if (ret < 0)
return ret;
}
frames = _snd_pcm_share_slave_forward(slave);
if (frames > 0) {
snd_pcm_sframes_t err;
- err = snd_pcm_mmap_forward(slave->pcm, frames);
+ err = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), frames);
assert(err == frames);
}
_snd_pcm_share_update(pcm);
return size;
}
-static snd_pcm_sframes_t snd_pcm_share_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size)
+static snd_pcm_sframes_t snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
+ snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t size)
{
snd_pcm_share_t *share = pcm->private_data;
snd_pcm_share_slave_t *slave = share->slave;
snd_pcm_sframes_t ret;
Pthread_mutex_lock(&slave->mutex);
- ret = _snd_pcm_share_mmap_forward(pcm, size);
+ ret = _snd_pcm_share_mmap_commit(pcm, offset, size);
Pthread_mutex_unlock(&slave->mutex);
return ret;
}
{
snd_pcm_share_t *share = pcm->private_data;
snd_pcm_share_slave_t *slave = share->slave;
+ snd_pcm_t *spcm = slave->pcm;
int err = 0;
if (share->state != SND_PCM_STATE_PREPARED)
return -EBADFD;
}
if (slave->running_count) {
snd_pcm_sframes_t sd;
- err = snd_pcm_delay(slave->pcm, &sd);
+ err = snd_pcm_delay(spcm, &sd);
if (err < 0)
goto _end;
- err = snd_pcm_rewind(slave->pcm, sd);
+ err = snd_pcm_rewind(spcm, sd);
if (err < 0)
goto _end;
}
assert(share->hw_ptr == 0);
- share->hw_ptr = *slave->pcm->hw_ptr;
- share->appl_ptr = *slave->pcm->appl_ptr;
+ share->hw_ptr = *spcm->hw_ptr;
+ share->appl_ptr = *spcm->appl_ptr;
while (xfer < hw_avail) {
snd_pcm_uframes_t frames = hw_avail - xfer;
snd_pcm_uframes_t offset = snd_pcm_mmap_offset(pcm);
}
snd_pcm_mmap_appl_forward(pcm, hw_avail);
if (slave->running_count == 0)
- snd_pcm_mmap_forward(slave->pcm, hw_avail);
+ snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), hw_avail);
}
if (slave->running_count == 0) {
- err = snd_pcm_start(slave->pcm);
+ err = snd_pcm_start(spcm);
if (err < 0)
goto _end;
}
readn: snd_pcm_mmap_readn,
rewind: snd_pcm_share_rewind,
avail_update: snd_pcm_share_avail_update,
- mmap_forward: snd_pcm_share_mmap_forward,
+ mmap_commit: snd_pcm_share_mmap_commit,
};
int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname,
return snd_pcm_shm_action(pcm);
}
-static snd_pcm_sframes_t snd_pcm_shm_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size)
+static snd_pcm_sframes_t snd_pcm_shm_mmap_commit(snd_pcm_t *pcm,
+ snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
+ snd_pcm_uframes_t size)
{
snd_pcm_shm_t *shm = pcm->private_data;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
- ctrl->cmd = SND_PCM_IOCTL_MMAP_FORWARD;
- ctrl->u.mmap_forward.frames = size;
+ ctrl->cmd = SND_PCM_IOCTL_MMAP_COMMIT;
+ ctrl->u.mmap_commit.offset = offset;
+ ctrl->u.mmap_commit.frames = size;
return snd_pcm_shm_action(pcm);
}
readi: snd_pcm_mmap_readi,
readn: snd_pcm_mmap_readn,
avail_update: snd_pcm_shm_avail_update,
- mmap_forward: snd_pcm_shm_mmap_forward,
+ mmap_commit: snd_pcm_shm_mmap_commit,
};
static int make_local_socket(const char *filename)
return res;
}
-static snd_pcm_sframes_t snd_pcm_surround_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t size)
+static snd_pcm_sframes_t snd_pcm_surround_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size)
{
int i;
snd_pcm_sframes_t res = -1, res1;
snd_pcm_surround_t *surr = pcm->private_data;
for (i = 0; i < surr->pcms; i++) {
- res1 = snd_pcm_mmap_forward(surr->pcm[i], size);
+ res1 = snd_pcm_mmap_commit(surr->pcm[i], offset, size);
if (res1 < 0)
return res1;
if (res < 0) {
readi: snd_pcm_surround_readi,
readn: snd_pcm_surround_readn,
avail_update: snd_pcm_surround_avail_update,
- mmap_forward: snd_pcm_surround_mmap_forward,
+ mmap_commit: snd_pcm_surround_mmap_commit,
};
int snd_pcm_surround_open(snd_pcm_t **pcmp, const char *name, int card, int dev,