2 * \file pcm/pcm_ioplug.c
4 * \brief I/O Plugin SDK
5 * \author Takashi Iwai <tiwai@suse.de>
9 * PCM - External I/O Plugin SDK
10 * Copyright (c) 2005 by Takashi Iwai <tiwai@suse.de>
13 * This library is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as
15 * published by the Free Software Foundation; either version 2.1 of
16 * the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 #include "pcm_local.h"
30 #include "pcm_ioplug.h"
31 #include "pcm_ext_parm.h"
32 #include "pcm_generic.h"
35 /* entry for static linking */
36 const char *_snd_module_pcm_ioplug = "";
42 typedef struct snd_pcm_ioplug_priv {
43 snd_pcm_ioplug_t *data;
44 struct snd_ext_parm params[SND_PCM_IOPLUG_HW_PARAMS];
45 snd_pcm_uframes_t last_hw;
46 snd_pcm_uframes_t avail_max;
47 snd_htimestamp_t trigger_tstamp;
50 static int snd_pcm_ioplug_drop(snd_pcm_t *pcm);
51 static int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm);
52 static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space);
53 static int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
55 /* update the hw pointer */
57 static void snd_pcm_ioplug_hw_ptr_update(snd_pcm_t *pcm)
59 ioplug_priv_t *io = pcm->private_data;
62 hw = io->data->callback->pointer(io->data);
64 snd_pcm_uframes_t delta;
65 snd_pcm_uframes_t avail;
67 if ((snd_pcm_uframes_t)hw >= io->last_hw)
68 delta = hw - io->last_hw;
70 const snd_pcm_uframes_t wrap_point =
71 (io->data->flags & SND_PCM_IOPLUG_FLAG_BOUNDARY_WA) ?
72 pcm->boundary : pcm->buffer_size;
73 delta = wrap_point + hw - io->last_hw;
75 snd_pcm_mmap_hw_forward(io->data->pcm, delta);
76 /* stop the stream if all samples are drained */
77 if (io->data->state == SND_PCM_STATE_DRAINING) {
78 avail = snd_pcm_mmap_avail(pcm);
79 if (avail >= pcm->buffer_size)
80 snd_pcm_ioplug_drop(pcm);
82 io->last_hw = (snd_pcm_uframes_t)hw;
84 if (io->data->state == SND_PCM_STATE_DRAINING)
85 snd_pcm_ioplug_drop(pcm);
87 io->data->state = SNDRV_PCM_STATE_XRUN;
91 static int snd_pcm_ioplug_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
93 memset(info, 0, sizeof(*info));
94 info->stream = pcm->stream;
97 snd_strlcpy((char *)info->id, pcm->name, sizeof(info->id));
98 snd_strlcpy((char *)info->name, pcm->name, sizeof(info->name));
99 snd_strlcpy((char *)info->subname, pcm->name, sizeof(info->subname));
101 info->subdevices_count = 1;
105 static int snd_pcm_ioplug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
107 return snd_pcm_channel_info_shm(pcm, info, -1);
110 static int snd_pcm_ioplug_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
112 ioplug_priv_t *io = pcm->private_data;
114 if (io->data->version >= 0x010001 &&
115 io->data->callback->delay)
116 return io->data->callback->delay(io->data, delayp);
118 snd_pcm_ioplug_hw_ptr_update(pcm);
119 *delayp = snd_pcm_mmap_delay(pcm);
124 static int snd_pcm_ioplug_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
126 ioplug_priv_t *io = pcm->private_data;
127 snd_pcm_sframes_t sd;
129 memset(status, 0, sizeof(*status));
130 snd_pcm_ioplug_hw_ptr_update(pcm);
131 status->state = io->data->state;
132 status->trigger_tstamp = io->trigger_tstamp;
133 gettimestamp(&status->tstamp, pcm->tstamp_type);
134 status->avail = snd_pcm_mmap_avail(pcm);
135 status->avail_max = io->avail_max;
136 status->appl_ptr = *pcm->appl.ptr;
137 status->hw_ptr = *pcm->hw.ptr;
138 if (snd_pcm_ioplug_delay(pcm, &sd) < 0)
139 sd = snd_pcm_mmap_delay(pcm);
144 static snd_pcm_state_t snd_pcm_ioplug_state(snd_pcm_t *pcm)
146 ioplug_priv_t *io = pcm->private_data;
147 return io->data->state;
150 static int snd_pcm_ioplug_hwsync(snd_pcm_t *pcm)
152 snd_pcm_ioplug_hw_ptr_update(pcm);
156 static int snd_pcm_ioplug_reset(snd_pcm_t *pcm)
158 ioplug_priv_t *io = pcm->private_data;
160 io->data->appl_ptr = 0;
161 io->data->hw_ptr = 0;
167 static int snd_pcm_ioplug_prepare(snd_pcm_t *pcm)
169 ioplug_priv_t *io = pcm->private_data;
172 snd_pcm_ioplug_reset(pcm);
173 if (io->data->callback->prepare) {
174 snd_pcm_unlock(pcm); /* to avoid deadlock */
175 err = io->data->callback->prepare(io->data);
181 io->data->state = SND_PCM_STATE_PREPARED;
185 static const int hw_params_type[SND_PCM_IOPLUG_HW_PARAMS] = {
186 [SND_PCM_IOPLUG_HW_ACCESS] = SND_PCM_HW_PARAM_ACCESS,
187 [SND_PCM_IOPLUG_HW_FORMAT] = SND_PCM_HW_PARAM_FORMAT,
188 [SND_PCM_IOPLUG_HW_CHANNELS] = SND_PCM_HW_PARAM_CHANNELS,
189 [SND_PCM_IOPLUG_HW_RATE] = SND_PCM_HW_PARAM_RATE,
190 [SND_PCM_IOPLUG_HW_PERIOD_BYTES] = SND_PCM_HW_PARAM_PERIOD_BYTES,
191 [SND_PCM_IOPLUG_HW_BUFFER_BYTES] = SND_PCM_HW_PARAM_BUFFER_BYTES,
192 [SND_PCM_IOPLUG_HW_PERIODS] = SND_PCM_HW_PARAM_PERIODS,
196 static int rule_mul(snd_pcm_hw_params_t *params, int x, int a, int b)
200 snd_interval_mul(hw_param_interval(params, a),
201 hw_param_interval(params, b), &t);
202 return snd_interval_refine(hw_param_interval(params, x), &t);
206 static int rule_div(snd_pcm_hw_params_t *params, int x, int a, int b)
210 snd_interval_div(hw_param_interval(params, a),
211 hw_param_interval(params, b), &t);
212 return snd_interval_refine(hw_param_interval(params, x), &t);
216 static int rule_muldivk(snd_pcm_hw_params_t *params, int x, int a, int b, int k)
220 snd_interval_muldivk(hw_param_interval(params, a),
221 hw_param_interval(params, b), k, &t);
222 return snd_interval_refine(hw_param_interval(params, x), &t);
226 static int rule_mulkdiv(snd_pcm_hw_params_t *params, int x, int a, int k, int b)
230 snd_interval_mulkdiv(hw_param_interval(params, a), k,
231 hw_param_interval(params, b), &t);
232 return snd_interval_refine(hw_param_interval(params, x), &t);
236 static void dump_parm(snd_pcm_hw_params_t *params)
239 snd_output_stdio_attach(&log, stderr, 0);
240 snd_pcm_hw_params_dump(params, log);
241 snd_output_close(log);
245 /* refine *_TIME and *_SIZE, then update *_BYTES */
246 static int refine_time_and_size(snd_pcm_hw_params_t *params,
247 int time, int size, int bytes)
249 int err, change1 = 0;
251 /* size = time * rate / 1000000 */
252 err = rule_muldivk(params, size, time,
253 SND_PCM_HW_PARAM_RATE, 1000000);
258 /* bytes = size * framebits / 8 */
259 err = rule_muldivk(params, bytes, size,
260 SND_PCM_HW_PARAM_FRAME_BITS, 8);
267 /* refine *_TIME and *_SIZE from *_BYTES */
268 static int refine_back_time_and_size(snd_pcm_hw_params_t *params,
269 int time, int size, int bytes)
273 /* size = bytes * 8 / framebits */
274 err = rule_mulkdiv(params, size, bytes, 8, SND_PCM_HW_PARAM_FRAME_BITS);
277 /* time = size * 1000000 / rate */
278 err = rule_mulkdiv(params, time, size, 1000000, SND_PCM_HW_PARAM_RATE);
285 static int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
287 int change = 0, change1, change2, err;
288 ioplug_priv_t *io = pcm->private_data;
289 struct snd_ext_parm *p;
293 for (i = SND_PCM_IOPLUG_HW_ACCESS; i <= SND_PCM_IOPLUG_HW_FORMAT; i++) {
294 err = snd_ext_parm_mask_refine(hw_param_mask(params, hw_params_type[i]),
301 for (; i <= SND_PCM_IOPLUG_HW_RATE; i++) {
302 err = snd_ext_parm_interval_refine(hw_param_interval(params, hw_params_type[i]),
309 if (params->rmask & ((1 << SND_PCM_HW_PARAM_ACCESS) |
310 (1 << SND_PCM_HW_PARAM_FORMAT) |
311 (1 << SND_PCM_HW_PARAM_SUBFORMAT) |
312 (1 << SND_PCM_HW_PARAM_CHANNELS) |
313 (1 << SND_PCM_HW_PARAM_RATE))) {
314 err = snd_pcm_hw_refine_soft(pcm, params);
320 change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
321 SND_PCM_HW_PARAM_PERIOD_SIZE,
322 SND_PCM_HW_PARAM_PERIOD_BYTES);
325 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES),
326 io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES);
332 err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
333 SND_PCM_HW_PARAM_PERIOD_SIZE,
334 SND_PCM_HW_PARAM_PERIOD_BYTES);
339 change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME,
340 SND_PCM_HW_PARAM_BUFFER_SIZE,
341 SND_PCM_HW_PARAM_BUFFER_BYTES);
348 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_BUFFER_BYTES),
349 io->params, SND_PCM_IOPLUG_HW_BUFFER_BYTES);
353 /* periods = buffer_bytes / period_bytes */
354 err = rule_div(params, SND_PCM_HW_PARAM_PERIODS,
355 SND_PCM_HW_PARAM_BUFFER_BYTES,
356 SND_PCM_HW_PARAM_PERIOD_BYTES);
360 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIODS),
361 io->params, SND_PCM_IOPLUG_HW_PERIODS);
365 /* buffer_bytes = periods * period_bytes */
366 err = rule_mul(params, SND_PCM_HW_PARAM_BUFFER_BYTES,
367 SND_PCM_HW_PARAM_PERIOD_BYTES,
368 SND_PCM_HW_PARAM_PERIODS);
377 err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME,
378 SND_PCM_HW_PARAM_BUFFER_SIZE,
379 SND_PCM_HW_PARAM_BUFFER_BYTES);
384 /* period_bytes = buffer_bytes / periods */
385 err = rule_div(params, SND_PCM_HW_PARAM_PERIOD_BYTES,
386 SND_PCM_HW_PARAM_BUFFER_BYTES,
387 SND_PCM_HW_PARAM_PERIODS);
391 /* update period_size and period_time */
393 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES),
394 io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES);
397 err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
398 SND_PCM_HW_PARAM_PERIOD_SIZE,
399 SND_PCM_HW_PARAM_PERIOD_BYTES);
404 params->info = SND_PCM_INFO_BLOCK_TRANSFER;
405 p = &io->params[SND_PCM_IOPLUG_HW_ACCESS];
407 for (i = 0; i < p->num_list; i++)
408 switch (p->list[i]) {
409 case SND_PCM_ACCESS_MMAP_INTERLEAVED:
410 case SND_PCM_ACCESS_RW_INTERLEAVED:
411 params->info |= SND_PCM_INFO_INTERLEAVED;
413 case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
414 case SND_PCM_ACCESS_RW_NONINTERLEAVED:
415 params->info |= SND_PCM_INFO_NONINTERLEAVED;
419 if (io->data->callback->pause)
420 params->info |= SND_PCM_INFO_PAUSE;
421 if (io->data->callback->resume)
422 params->info |= SND_PCM_INFO_RESUME;
425 fprintf(stderr, "XXX\n");
431 static int snd_pcm_ioplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
433 ioplug_priv_t *io = pcm->private_data;
436 INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access);
437 INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format);
438 INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels);
439 INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0);
440 INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0);
441 INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size);
442 if (io->data->callback->hw_params) {
443 err = io->data->callback->hw_params(io->data, params);
446 INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access);
447 INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format);
448 INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels);
449 INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0);
450 INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0);
451 INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size);
456 static int snd_pcm_ioplug_hw_free(snd_pcm_t *pcm)
458 ioplug_priv_t *io = pcm->private_data;
460 if (io->data->callback->hw_free)
461 return io->data->callback->hw_free(io->data);
465 static int snd_pcm_ioplug_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
467 ioplug_priv_t *io = pcm->private_data;
470 if (!io->data->callback->sw_params)
473 snd_pcm_unlock(pcm); /* to avoid deadlock */
474 err = io->data->callback->sw_params(io->data, params);
481 static int snd_pcm_ioplug_start(snd_pcm_t *pcm)
483 ioplug_priv_t *io = pcm->private_data;
486 if (io->data->state != SND_PCM_STATE_PREPARED)
489 err = io->data->callback->start(io->data);
493 gettimestamp(&io->trigger_tstamp, pcm->tstamp_type);
494 io->data->state = SND_PCM_STATE_RUNNING;
499 static int snd_pcm_ioplug_drop(snd_pcm_t *pcm)
501 ioplug_priv_t *io = pcm->private_data;
503 if (io->data->state == SND_PCM_STATE_OPEN)
506 io->data->callback->stop(io->data);
508 gettimestamp(&io->trigger_tstamp, pcm->tstamp_type);
509 io->data->state = SND_PCM_STATE_SETUP;
514 static int ioplug_drain_via_poll(snd_pcm_t *pcm)
516 ioplug_priv_t *io = pcm->private_data;
518 while (io->data->state == SND_PCM_STATE_DRAINING) {
519 snd_pcm_ioplug_hw_ptr_update(pcm);
520 if (io->data->state != SND_PCM_STATE_DRAINING)
522 /* in non-blocking mode, let application to poll() by itself */
523 if (io->data->nonblock)
525 if (snd_pcm_wait_nocheck(pcm, SND_PCM_WAIT_DRAIN) < 0)
529 return 0; /* force to drop at error */
532 /* need own locking */
533 static int snd_pcm_ioplug_drain(snd_pcm_t *pcm)
535 ioplug_priv_t *io = pcm->private_data;
539 switch (io->data->state) {
540 case SND_PCM_STATE_OPEN:
541 case SND_PCM_STATE_DISCONNECTED:
542 case SND_PCM_STATE_SUSPENDED:
545 case SND_PCM_STATE_PREPARED:
546 if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
547 if (!io->data->callback->drain) {
548 err = snd_pcm_ioplug_start(pcm);
552 io->data->state = SND_PCM_STATE_DRAINING;
555 case SND_PCM_STATE_RUNNING:
556 io->data->state = SND_PCM_STATE_DRAINING;
562 if (io->data->state == SND_PCM_STATE_DRAINING) {
563 if (io->data->callback->drain) {
564 snd_pcm_unlock(pcm); /* let plugin own locking */
565 err = io->data->callback->drain(io->data);
568 err = ioplug_drain_via_poll(pcm);
573 if (!err && io->data->state != SND_PCM_STATE_SETUP)
574 snd_pcm_ioplug_drop(pcm);
579 static int snd_pcm_ioplug_pause(snd_pcm_t *pcm, int enable)
581 ioplug_priv_t *io = pcm->private_data;
582 static const snd_pcm_state_t states[2] = {
583 SND_PCM_STATE_RUNNING, SND_PCM_STATE_PAUSED
589 if (io->data->state != states[prev])
591 if (io->data->callback->pause) {
592 err = io->data->callback->pause(io->data, enable);
596 io->data->state = states[enable];
600 static snd_pcm_sframes_t snd_pcm_ioplug_rewindable(snd_pcm_t *pcm)
602 return snd_pcm_mmap_hw_rewindable(pcm);
605 static snd_pcm_sframes_t snd_pcm_ioplug_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
607 snd_pcm_mmap_appl_backward(pcm, frames);
611 static snd_pcm_sframes_t snd_pcm_ioplug_forwardable(snd_pcm_t *pcm)
613 return snd_pcm_mmap_avail(pcm);
616 static snd_pcm_sframes_t snd_pcm_ioplug_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
618 snd_pcm_mmap_appl_forward(pcm, frames);
622 /* need own locking */
623 static int snd_pcm_ioplug_resume(snd_pcm_t *pcm)
625 ioplug_priv_t *io = pcm->private_data;
627 if (io->data->callback->resume)
628 io->data->callback->resume(io->data);
633 static snd_pcm_sframes_t ioplug_priv_transfer_areas(snd_pcm_t *pcm,
634 const snd_pcm_channel_area_t *areas,
635 snd_pcm_uframes_t offset,
636 snd_pcm_uframes_t size)
638 ioplug_priv_t *io = pcm->private_data;
639 snd_pcm_sframes_t result;
643 if (io->data->callback->transfer)
644 result = io->data->callback->transfer(io->data, areas, offset, size);
648 snd_pcm_mmap_appl_forward(pcm, result);
652 static snd_pcm_sframes_t snd_pcm_ioplug_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
655 return snd_pcm_mmap_writei(pcm, buffer, size);
657 snd_pcm_channel_area_t areas[pcm->channels];
658 snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
659 return snd_pcm_write_areas(pcm, areas, 0, size,
660 ioplug_priv_transfer_areas);
664 static snd_pcm_sframes_t snd_pcm_ioplug_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
667 return snd_pcm_mmap_writen(pcm, bufs, size);
669 snd_pcm_channel_area_t areas[pcm->channels];
670 snd_pcm_areas_from_bufs(pcm, areas, bufs);
671 return snd_pcm_write_areas(pcm, areas, 0, size,
672 ioplug_priv_transfer_areas);
676 static snd_pcm_sframes_t snd_pcm_ioplug_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
679 return snd_pcm_mmap_readi(pcm, buffer, size);
681 snd_pcm_channel_area_t areas[pcm->channels];
682 snd_pcm_areas_from_buf(pcm, areas, buffer);
683 return snd_pcm_read_areas(pcm, areas, 0, size,
684 ioplug_priv_transfer_areas);
688 static snd_pcm_sframes_t snd_pcm_ioplug_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
691 return snd_pcm_mmap_readn(pcm, bufs, size);
693 snd_pcm_channel_area_t areas[pcm->channels];
694 snd_pcm_areas_from_bufs(pcm, areas, bufs);
695 return snd_pcm_read_areas(pcm, areas, 0, size,
696 ioplug_priv_transfer_areas);
700 static int snd_pcm_ioplug_mmap_begin_capture(snd_pcm_t *pcm,
701 const snd_pcm_channel_area_t **areas,
702 snd_pcm_uframes_t *offset,
703 snd_pcm_uframes_t *frames)
705 ioplug_priv_t *io = pcm->private_data;
708 err = __snd_pcm_mmap_begin_generic(pcm, areas, offset, frames);
712 if (io->data->callback->transfer &&
713 pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
714 pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
715 snd_pcm_sframes_t result;
716 result = io->data->callback->transfer(io->data, *areas, *offset, *frames);
724 static int snd_pcm_ioplug_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas,
725 snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames)
727 if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
728 return __snd_pcm_mmap_begin_generic(pcm, areas, offset, frames);
729 return snd_pcm_ioplug_mmap_begin_capture(pcm, areas, offset, frames);
732 static snd_pcm_sframes_t snd_pcm_ioplug_mmap_commit(snd_pcm_t *pcm,
733 snd_pcm_uframes_t offset,
734 snd_pcm_uframes_t size)
736 if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
737 pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
738 pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
739 const snd_pcm_channel_area_t *areas;
740 snd_pcm_uframes_t ofs, frames = size;
742 __snd_pcm_mmap_begin_generic(pcm, &areas, &ofs, &frames);
745 return ioplug_priv_transfer_areas(pcm, areas, offset, frames);
748 snd_pcm_mmap_appl_forward(pcm, size);
752 static snd_pcm_sframes_t snd_pcm_ioplug_avail_update(snd_pcm_t *pcm)
754 ioplug_priv_t *io = pcm->private_data;
755 snd_pcm_uframes_t avail;
757 snd_pcm_ioplug_hw_ptr_update(pcm);
758 if (io->data->state == SND_PCM_STATE_XRUN)
761 avail = snd_pcm_mmap_avail(pcm);
762 if (avail > io->avail_max)
763 io->avail_max = avail;
764 return (snd_pcm_sframes_t)avail;
767 static int snd_pcm_ioplug_nonblock(snd_pcm_t *pcm, int nonblock)
769 ioplug_priv_t *io = pcm->private_data;
771 io->data->nonblock = nonblock;
775 static int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm)
777 ioplug_priv_t *io = pcm->private_data;
780 if (io->data->callback->poll_descriptors_count) {
781 snd_pcm_unlock(pcm); /* to avoid deadlock */
782 err = io->data->callback->poll_descriptors_count(io->data);
788 static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
790 ioplug_priv_t *io = pcm->private_data;
793 if (io->data->callback->poll_descriptors) {
794 snd_pcm_unlock(pcm); /* to avoid deadlock */
795 err = io->data->callback->poll_descriptors(io->data, pfds, space);
799 if (pcm->poll_fd < 0)
801 if (space >= 1 && pfds) {
802 pfds->fd = pcm->poll_fd;
803 pfds->events = pcm->poll_events | POLLERR | POLLNVAL;
810 static int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
812 ioplug_priv_t *io = pcm->private_data;
815 if (io->data->callback->poll_revents) {
816 snd_pcm_unlock(pcm); /* to avoid deadlock */
817 err = io->data->callback->poll_revents(io->data, pfds, nfds, revents);
820 *revents = pfds->revents;
826 static int snd_pcm_ioplug_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
831 static int snd_pcm_ioplug_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
832 int sig ATTRIBUTE_UNUSED,
833 pid_t pid ATTRIBUTE_UNUSED)
838 static int snd_pcm_ioplug_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
843 static snd_pcm_chmap_query_t **snd_pcm_ioplug_query_chmaps(snd_pcm_t *pcm)
845 ioplug_priv_t *io = pcm->private_data;
847 if (io->data->version >= 0x010002 &&
848 io->data->callback->query_chmaps)
849 return io->data->callback->query_chmaps(io->data);
853 static snd_pcm_chmap_t *snd_pcm_ioplug_get_chmap(snd_pcm_t *pcm)
855 ioplug_priv_t *io = pcm->private_data;
857 if (io->data->version >= 0x010002 &&
858 io->data->callback->get_chmap)
859 return io->data->callback->get_chmap(io->data);
863 static int snd_pcm_ioplug_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
865 ioplug_priv_t *io = pcm->private_data;
867 if (io->data->version >= 0x010002 &&
868 io->data->callback->set_chmap)
869 return io->data->callback->set_chmap(io->data, map);
873 static void snd_pcm_ioplug_dump(snd_pcm_t *pcm, snd_output_t *out)
875 ioplug_priv_t *io = pcm->private_data;
877 if (io->data->callback->dump)
878 io->data->callback->dump(io->data, out);
881 snd_output_printf(out, "%s\n", io->data->name);
883 snd_output_printf(out, "IO-PCM Plugin\n");
885 snd_output_printf(out, "Its setup is:\n");
886 snd_pcm_dump_setup(pcm, out);
891 static void clear_io_params(ioplug_priv_t *io)
894 for (i = 0; i < SND_PCM_IOPLUG_HW_PARAMS; i++)
895 snd_ext_parm_clear(&io->params[i]);
898 static int snd_pcm_ioplug_close(snd_pcm_t *pcm)
900 ioplug_priv_t *io = pcm->private_data;
903 if (io->data->callback->close)
904 io->data->callback->close(io->data);
910 static const snd_pcm_ops_t snd_pcm_ioplug_ops = {
911 .close = snd_pcm_ioplug_close,
912 .nonblock = snd_pcm_ioplug_nonblock,
913 .async = snd_pcm_ioplug_async,
914 .info = snd_pcm_ioplug_info,
915 .hw_refine = snd_pcm_ioplug_hw_refine,
916 .hw_params = snd_pcm_ioplug_hw_params,
917 .hw_free = snd_pcm_ioplug_hw_free,
918 .sw_params = snd_pcm_ioplug_sw_params,
919 .channel_info = snd_pcm_ioplug_channel_info,
920 .dump = snd_pcm_ioplug_dump,
921 .mmap = snd_pcm_ioplug_mmap,
922 .munmap = snd_pcm_ioplug_munmap,
923 .query_chmaps = snd_pcm_ioplug_query_chmaps,
924 .get_chmap = snd_pcm_ioplug_get_chmap,
925 .set_chmap = snd_pcm_ioplug_set_chmap,
928 static const snd_pcm_fast_ops_t snd_pcm_ioplug_fast_ops = {
929 .status = snd_pcm_ioplug_status,
930 .prepare = snd_pcm_ioplug_prepare,
931 .reset = snd_pcm_ioplug_reset,
932 .start = snd_pcm_ioplug_start,
933 .drop = snd_pcm_ioplug_drop,
934 .drain = snd_pcm_ioplug_drain,
935 .pause = snd_pcm_ioplug_pause,
936 .state = snd_pcm_ioplug_state,
937 .hwsync = snd_pcm_ioplug_hwsync,
938 .delay = snd_pcm_ioplug_delay,
939 .resume = snd_pcm_ioplug_resume,
943 .rewindable = snd_pcm_ioplug_rewindable,
944 .rewind = snd_pcm_ioplug_rewind,
945 .forwardable = snd_pcm_ioplug_forwardable,
946 .forward = snd_pcm_ioplug_forward,
947 .writei = snd_pcm_ioplug_writei,
948 .writen = snd_pcm_ioplug_writen,
949 .readi = snd_pcm_ioplug_readi,
950 .readn = snd_pcm_ioplug_readn,
951 .avail_update = snd_pcm_ioplug_avail_update,
952 .mmap_commit = snd_pcm_ioplug_mmap_commit,
953 .htimestamp = snd_pcm_generic_real_htimestamp,
954 .poll_descriptors_count = snd_pcm_ioplug_poll_descriptors_count,
955 .poll_descriptors = snd_pcm_ioplug_poll_descriptors,
956 .poll_revents = snd_pcm_ioplug_poll_revents,
957 .mmap_begin = snd_pcm_ioplug_mmap_begin,
960 #endif /* !DOC_HIDDEN */
966 /*! \page pcm_external_plugins PCM External Plugin SDK
968 \section pcm_ioplug External Plugin: I/O Plugin
970 The I/O-type plugin is a PCM plugin to work as the input or output terminal point,
971 i.e. as a user-space PCM driver.
973 The new plugin is created via #snd_pcm_ioplug_create() function.
974 The first argument is a pointer of the pluging information. Some of
975 this struct must be initialized in prior to call
976 #snd_pcm_ioplug_create(). Then the function fills other fields in
977 return. The rest arguments, name, stream and mode, are usually
978 identical with the values passed from the ALSA plugin constructor.
980 The following fields are mandatory: version, name, callback.
981 Otherfields are optional and should be initialized with zero.
983 The constant #SND_PCM_IOPLUG_VERSION must be passed to the version
984 field for the version check in alsa-lib. A non-NULL ASCII string
985 has to be passed to the name field. The callback field contains the
986 table of callback functions for this plugin (defined as
987 #snd_pcm_ioplug_callback_t).
989 flags field specifies the optional bit-flags. poll_fd and poll_events
990 specify the poll file descriptor and the corresponding poll events
991 (POLLIN, POLLOUT) for the plugin. If the plugin requires multiple
992 poll descriptors or poll descriptor(s) dynamically varying, set
993 poll_descriptors and poll_descriptors_count callbacks to the callback
994 table. Then the poll_fd and poll_events field are ignored.
996 mmap_rw specifies whether the plugin behaves in the pseudo mmap mode.
997 When this value is set to 1, the plugin creates always a local buffer
998 and performs read/write calls using this buffer as if it's mmapped.
999 The address of local buffer can be obtained via
1000 #snd_pcm_ioplug_mmap_areas() function.
1001 When poll_fd, poll_events and mmap_rw fields are changed after
1002 #snd_pcm_ioplug_create(), call #snd_pcm_ioplug_reinit_status() to
1003 reflect the changes.
1005 The driver can set an arbitrary value (pointer) to private_data
1006 field to refer its own data in the callbacks.
1008 The rest fields are filled by #snd_pcm_ioplug_create(). The pcm field
1009 is the resultant PCM handle. The others are the current status of the
1012 The callback functions in #snd_pcm_ioplug_callback_t define the real
1013 behavior of the driver.
1014 At least, start, stop and pointer callbacks must be given. Other
1015 callbacks are optional. The start and stop callbacks are called when
1016 the PCM stream is started and stopped, repsectively. The pointer
1017 callback returns the current DMA position, which may be called at any
1020 The transfer callback is called when any data transfer happens. It
1021 receives the area array, offset and the size to transfer. The area
1022 array contains the array of snd_pcm_channel_area_t with the elements
1023 of number of channels.
1025 When the PCM is closed, close callback is called. If the driver
1026 allocates any internal buffers, they should be released in this
1027 callback. The hw_params and hw_free callbacks are called when
1028 hw_params are set and reset, respectively. Note that they may be
1029 called multiple times according to the application. Similarly,
1030 sw_params callback is called when sw_params is set or changed.
1032 The prepare, drain, pause and resume callbacks are called when
1033 #snd_pcm_prepare(), #snd_pcm_drain(), #snd_pcm_pause(), and
1034 #snd_pcm_resume() are called. The poll_descriptors_count and
1035 poll_descriptors callbacks are used to return the multiple or dynamic
1036 poll descriptors as mentioned above. The poll_revents callback is
1037 used to modify poll events. If the driver needs to mangle the native
1038 poll events to proper poll events for PCM, you can do it in this
1041 Finally, the dump callback is used to print the status of the plugin.
1043 Note that some callbacks (start, stop, pointer, transfer and pause)
1044 may be called inside the internal pthread mutex, and they shouldn't
1045 call the PCM functions again unnecessarily from the callback itself;
1046 otherwise it may lead to a deadlock.
1048 The hw_params constraints can be defined via either
1049 #snd_pcm_ioplug_set_param_minmax() and #snd_pcm_ioplug_set_param_list()
1050 functions after calling #snd_pcm_ioplug_create().
1051 The former defines the minimal and maximal acceptable values for the
1052 given hw_params parameter (SND_PCM_IOPLUG_HW_XXX).
1053 This function can't be used for the format parameter. The latter
1054 function specifies the available parameter values as the list.
1056 To clear the parameter constraints, call #snd_pcm_ioplug_params_reset() function.
1061 * \brief Create an ioplug instance
1062 * \param ioplug the ioplug handle
1063 * \param name name of PCM
1064 * \param stream stream direction
1065 * \param mode PCM open mode
1066 * \return 0 if successful, or a negative error code
1068 * Creates the ioplug instance.
1070 * The callback is the mandatory field of ioplug handle. At least, start, stop and
1071 * pointer callbacks must be set before calling this function.
1074 int snd_pcm_ioplug_create(snd_pcm_ioplug_t *ioplug, const char *name,
1075 snd_pcm_stream_t stream, int mode)
1081 assert(ioplug && ioplug->callback);
1082 assert(ioplug->callback->start &&
1083 ioplug->callback->stop &&
1084 ioplug->callback->pointer);
1086 /* We support 1.0.0 to current */
1087 if (ioplug->version < 0x010000 ||
1088 ioplug->version > SND_PCM_IOPLUG_VERSION) {
1089 snd_error(PCM, "ioplug: Plugin version mismatch: 0x%x",
1095 io = calloc(1, sizeof(*io));
1100 ioplug->state = SND_PCM_STATE_OPEN;
1101 ioplug->stream = stream;
1103 err = snd_pcm_new(&pcm, SND_PCM_TYPE_IOPLUG, name, stream, mode);
1110 pcm->ops = &snd_pcm_ioplug_ops;
1111 pcm->fast_ops = &snd_pcm_ioplug_fast_ops;
1112 pcm->private_data = io;
1114 snd_pcm_set_hw_ptr(pcm, &ioplug->hw_ptr, -1, 0);
1115 snd_pcm_set_appl_ptr(pcm, &ioplug->appl_ptr, -1, 0);
1117 snd_pcm_ioplug_reinit_status(ioplug);
1123 * \brief Delete the ioplug instance
1124 * \param ioplug the ioplug handle
1125 * \return 0 if successful, or a negative error code
1127 int snd_pcm_ioplug_delete(snd_pcm_ioplug_t *ioplug)
1129 return snd_pcm_close(ioplug->pcm);
1134 * \brief Reset ioplug parameters
1135 * \param ioplug the ioplug handle
1137 * Resets the all parameters for the given ioplug handle.
1139 void snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t *ioplug)
1141 ioplug_priv_t *io = ioplug->pcm->private_data;
1142 clear_io_params(io);
1146 * \brief Set parameter as the list
1147 * \param ioplug the ioplug handle
1148 * \param type parameter type
1149 * \param num_list number of available values
1150 * \param list the list of available values
1151 * \return 0 if successful, or a negative error code
1153 * Sets the parameter as the list.
1154 * The available values of the given parameter type is restricted to the ones of the given list.
1156 int snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t *ioplug, int type, unsigned int num_list, const unsigned int *list)
1158 ioplug_priv_t *io = ioplug->pcm->private_data;
1159 if (type < 0 || type >= SND_PCM_IOPLUG_HW_PARAMS) {
1160 snd_error(PCM, "IOPLUG: invalid parameter type %d", type);
1163 if (type == SND_PCM_IOPLUG_HW_PERIODS)
1164 io->params[type].integer = 1;
1165 return snd_ext_parm_set_list(&io->params[type], num_list, list);
1169 * \brief Set parameter as the min/max values
1170 * \param ioplug the ioplug handle
1171 * \param type parameter type
1172 * \param min the minimum value
1173 * \param max the maximum value
1174 * \return 0 if successful, or a negative error code
1176 * Sets the parameter as the min/max values.
1177 * The available values of the given parameter type is restricted between the given
1178 * minimum and maximum values.
1180 int snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *ioplug, int type, unsigned int min, unsigned int max)
1182 ioplug_priv_t *io = ioplug->pcm->private_data;
1183 if (type < 0 || type >= SND_PCM_IOPLUG_HW_PARAMS) {
1184 snd_error(PCM, "IOPLUG: invalid parameter type %d", type);
1187 if (type == SND_PCM_IOPLUG_HW_ACCESS || type == SND_PCM_IOPLUG_HW_FORMAT) {
1188 snd_error(PCM, "IOPLUG: invalid parameter type %d", type);
1191 if (type == SND_PCM_IOPLUG_HW_PERIODS)
1192 io->params[type].integer = 1;
1193 return snd_ext_parm_set_minmax(&io->params[type], min, max);
1197 * \brief Reinitialize the poll and mmap status
1198 * \param ioplug the ioplug handle
1199 * \return 0 if successful, or a negative error code
1201 * Reinitializes the poll and the mmap status of the PCM.
1202 * Call this function to propagate the status change in the ioplug instance to
1203 * its PCM internals.
1205 int snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug)
1207 ioplug->pcm->poll_fd = ioplug->poll_fd;
1208 ioplug->pcm->poll_events = ioplug->poll_events;
1209 if (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC)
1210 ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC;
1212 ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
1213 ioplug->pcm->mmap_rw = ioplug->mmap_rw;
1218 * \brief Get mmap area of ioplug
1219 * \param ioplug the ioplug handle
1220 * \return the mmap channel areas if available, or NULL
1222 * Returns the mmap channel areas if available. When mmap_rw field is not set,
1223 * this function always returns NULL.
1225 const snd_pcm_channel_area_t *snd_pcm_ioplug_mmap_areas(snd_pcm_ioplug_t *ioplug)
1227 if (ioplug->mmap_rw)
1228 return snd_pcm_mmap_areas(ioplug->pcm);
1233 * \brief Change the ioplug PCM status
1234 * \param ioplug the ioplug handle
1235 * \param state the PCM status
1236 * \return zero if successful or a negative error code
1238 * Changes the PCM status of the ioplug to the given value.
1239 * This function can be used for external plugins to notify the status
1240 * change, e.g. XRUN.
1242 int snd_pcm_ioplug_set_state(snd_pcm_ioplug_t *ioplug, snd_pcm_state_t state)
1244 ioplug->state = state;
1249 * \brief Get the available frames. This function can be used to calculate the
1250 * the available frames before calling #snd_pcm_avail_update()
1251 * \param ioplug the ioplug handle
1252 * \param hw_ptr hardware pointer in frames
1253 * \param appl_ptr application pointer in frames
1254 * \return available frames for the application
1256 snd_pcm_uframes_t snd_pcm_ioplug_avail(const snd_pcm_ioplug_t * const ioplug,
1257 const snd_pcm_uframes_t hw_ptr,
1258 const snd_pcm_uframes_t appl_ptr)
1260 return __snd_pcm_avail(ioplug->pcm, hw_ptr, appl_ptr);
1264 * \brief Get the available frames. This function can be used to calculate the
1265 * the available frames before calling #snd_pcm_avail_update()
1266 * \param ioplug the ioplug handle
1267 * \param hw_ptr hardware pointer in frames
1268 * \param appl_ptr application pointer in frames
1269 * \return available frames for the hardware
1271 snd_pcm_uframes_t snd_pcm_ioplug_hw_avail(const snd_pcm_ioplug_t * const ioplug,
1272 const snd_pcm_uframes_t hw_ptr,
1273 const snd_pcm_uframes_t appl_ptr)
1275 /* available data/space which can be transferred by the user
1278 const snd_pcm_uframes_t user_avail = snd_pcm_ioplug_avail(ioplug,
1282 if (user_avail > ioplug->pcm->buffer_size) {
1283 /* there was an Xrun */
1286 /* available data/space which can be transferred by the DMA */
1287 return ioplug->pcm->buffer_size - user_avail;