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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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];
46 snd_pcm_uframes_t avail_max;
47 snd_htimestamp_t trigger_tstamp;
50 /* update the hw pointer */
51 static void snd_pcm_ioplug_hw_ptr_update(snd_pcm_t *pcm)
53 ioplug_priv_t *io = pcm->private_data;
56 hw = io->data->callback->pointer(io->data);
59 if ((unsigned int)hw >= io->last_hw)
60 delta = hw - io->last_hw;
62 delta = pcm->buffer_size + hw - io->last_hw;
63 io->data->hw_ptr += delta;
66 io->data->state = SNDRV_PCM_STATE_XRUN;
69 static int snd_pcm_ioplug_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
71 memset(info, 0, sizeof(*info));
72 info->stream = pcm->stream;
75 strncpy((char *)info->id, pcm->name, sizeof(info->id));
76 strncpy((char *)info->name, pcm->name, sizeof(info->name));
77 strncpy((char *)info->subname, pcm->name, sizeof(info->subname));
79 info->subdevices_count = 1;
83 static int snd_pcm_ioplug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
85 return snd_pcm_channel_info_shm(pcm, info, -1);
88 static int snd_pcm_ioplug_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
90 ioplug_priv_t *io = pcm->private_data;
92 memset(status, 0, sizeof(*status));
93 snd_pcm_ioplug_hw_ptr_update(pcm);
94 status->state = io->data->state;
95 status->trigger_tstamp = io->trigger_tstamp;
96 status->avail = snd_pcm_mmap_avail(pcm);
97 status->avail_max = io->avail_max;
101 static snd_pcm_state_t snd_pcm_ioplug_state(snd_pcm_t *pcm)
103 ioplug_priv_t *io = pcm->private_data;
104 return io->data->state;
107 static int snd_pcm_ioplug_hwsync(snd_pcm_t *pcm)
109 snd_pcm_ioplug_hw_ptr_update(pcm);
113 static int snd_pcm_ioplug_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
115 ioplug_priv_t *io = pcm->private_data;
117 if (io->data->version >= 0x010001 &&
118 io->data->callback->delay)
119 return io->data->callback->delay(io->data, delayp);
121 snd_pcm_ioplug_hw_ptr_update(pcm);
122 *delayp = snd_pcm_mmap_hw_avail(pcm);
127 static int snd_pcm_ioplug_reset(snd_pcm_t *pcm)
129 ioplug_priv_t *io = pcm->private_data;
131 io->data->appl_ptr = 0;
132 io->data->hw_ptr = 0;
138 static int snd_pcm_ioplug_prepare(snd_pcm_t *pcm)
140 ioplug_priv_t *io = pcm->private_data;
142 io->data->state = SND_PCM_STATE_PREPARED;
143 snd_pcm_ioplug_reset(pcm);
144 if (io->data->callback->prepare)
145 return io->data->callback->prepare(io->data);
149 static const int hw_params_type[SND_PCM_IOPLUG_HW_PARAMS] = {
150 [SND_PCM_IOPLUG_HW_ACCESS] = SND_PCM_HW_PARAM_ACCESS,
151 [SND_PCM_IOPLUG_HW_FORMAT] = SND_PCM_HW_PARAM_FORMAT,
152 [SND_PCM_IOPLUG_HW_CHANNELS] = SND_PCM_HW_PARAM_CHANNELS,
153 [SND_PCM_IOPLUG_HW_RATE] = SND_PCM_HW_PARAM_RATE,
154 [SND_PCM_IOPLUG_HW_PERIOD_BYTES] = SND_PCM_HW_PARAM_PERIOD_BYTES,
155 [SND_PCM_IOPLUG_HW_BUFFER_BYTES] = SND_PCM_HW_PARAM_BUFFER_BYTES,
156 [SND_PCM_IOPLUG_HW_PERIODS] = SND_PCM_HW_PARAM_PERIODS,
160 static int rule_mul(snd_pcm_hw_params_t *params, int x, int a, int b)
164 snd_interval_mul(hw_param_interval(params, a),
165 hw_param_interval(params, b), &t);
166 return snd_interval_refine(hw_param_interval(params, x), &t);
170 static int rule_div(snd_pcm_hw_params_t *params, int x, int a, int b)
174 snd_interval_div(hw_param_interval(params, a),
175 hw_param_interval(params, b), &t);
176 return snd_interval_refine(hw_param_interval(params, x), &t);
180 static int rule_muldivk(snd_pcm_hw_params_t *params, int x, int a, int b, int k)
184 snd_interval_muldivk(hw_param_interval(params, a),
185 hw_param_interval(params, b), k, &t);
186 return snd_interval_refine(hw_param_interval(params, x), &t);
190 static int rule_mulkdiv(snd_pcm_hw_params_t *params, int x, int a, int k, int b)
194 snd_interval_mulkdiv(hw_param_interval(params, a), k,
195 hw_param_interval(params, b), &t);
196 return snd_interval_refine(hw_param_interval(params, x), &t);
200 static void dump_parm(snd_pcm_hw_params_t *params)
203 snd_output_stdio_attach(&log, stderr, 0);
204 snd_pcm_hw_params_dump(params, log);
205 snd_output_close(log);
209 /* refine *_TIME and *_SIZE, then update *_BYTES */
210 static int refine_time_and_size(snd_pcm_hw_params_t *params,
211 int time, int size, int bytes)
213 int err, change1 = 0;
215 /* size = time * rate / 1000000 */
216 err = rule_muldivk(params, size, time,
217 SND_PCM_HW_PARAM_RATE, 1000000);
222 /* bytes = size * framebits / 8 */
223 err = rule_muldivk(params, bytes, size,
224 SND_PCM_HW_PARAM_FRAME_BITS, 8);
231 /* refine *_TIME and *_SIZE from *_BYTES */
232 static int refine_back_time_and_size(snd_pcm_hw_params_t *params,
233 int time, int size, int bytes)
237 /* size = bytes * 8 / framebits */
238 err = rule_mulkdiv(params, size, bytes, 8, SND_PCM_HW_PARAM_FRAME_BITS);
241 /* time = size * 1000000 / rate */
242 err = rule_mulkdiv(params, time, size, 1000000, SND_PCM_HW_PARAM_RATE);
249 static int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
251 int change = 0, change1, change2, err;
252 ioplug_priv_t *io = pcm->private_data;
253 struct snd_ext_parm *p;
257 for (i = SND_PCM_IOPLUG_HW_ACCESS; i <= SND_PCM_IOPLUG_HW_FORMAT; i++) {
258 err = snd_ext_parm_mask_refine(hw_param_mask(params, hw_params_type[i]),
265 for (; i <= SND_PCM_IOPLUG_HW_RATE; i++) {
266 err = snd_ext_parm_interval_refine(hw_param_interval(params, hw_params_type[i]),
273 if (params->rmask & ((1 << SND_PCM_HW_PARAM_ACCESS) |
274 (1 << SND_PCM_HW_PARAM_FORMAT) |
275 (1 << SND_PCM_HW_PARAM_SUBFORMAT) |
276 (1 << SND_PCM_HW_PARAM_CHANNELS) |
277 (1 << SND_PCM_HW_PARAM_RATE))) {
278 err = snd_pcm_hw_refine_soft(pcm, params);
284 change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
285 SND_PCM_HW_PARAM_PERIOD_SIZE,
286 SND_PCM_HW_PARAM_PERIOD_BYTES);
289 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES),
290 io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES);
296 err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
297 SND_PCM_HW_PARAM_PERIOD_SIZE,
298 SND_PCM_HW_PARAM_PERIOD_BYTES);
303 change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME,
304 SND_PCM_HW_PARAM_BUFFER_SIZE,
305 SND_PCM_HW_PARAM_BUFFER_BYTES);
312 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_BUFFER_BYTES),
313 io->params, SND_PCM_IOPLUG_HW_BUFFER_BYTES);
317 /* periods = buffer_bytes / period_bytes */
318 err = rule_div(params, SND_PCM_HW_PARAM_PERIODS,
319 SND_PCM_HW_PARAM_BUFFER_BYTES,
320 SND_PCM_HW_PARAM_PERIOD_BYTES);
324 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIODS),
325 io->params, SND_PCM_IOPLUG_HW_PERIODS);
329 /* buffer_bytes = periods * period_bytes */
330 err = rule_mul(params, SND_PCM_HW_PARAM_BUFFER_BYTES,
331 SND_PCM_HW_PARAM_PERIOD_BYTES,
332 SND_PCM_HW_PARAM_PERIODS);
341 err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME,
342 SND_PCM_HW_PARAM_BUFFER_SIZE,
343 SND_PCM_HW_PARAM_BUFFER_BYTES);
348 /* period_bytes = buffer_bytes / periods */
349 err = rule_div(params, SND_PCM_HW_PARAM_PERIOD_BYTES,
350 SND_PCM_HW_PARAM_BUFFER_BYTES,
351 SND_PCM_HW_PARAM_PERIODS);
355 /* update period_size and period_time */
357 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES),
358 io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES);
361 err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
362 SND_PCM_HW_PARAM_PERIOD_SIZE,
363 SND_PCM_HW_PARAM_PERIOD_BYTES);
368 params->info = SND_PCM_INFO_BLOCK_TRANSFER;
369 p = &io->params[SND_PCM_IOPLUG_HW_ACCESS];
371 for (i = 0; i < p->num_list; i++)
372 switch (p->list[i]) {
373 case SND_PCM_ACCESS_MMAP_INTERLEAVED:
374 case SND_PCM_ACCESS_RW_INTERLEAVED:
375 params->info |= SND_PCM_INFO_INTERLEAVED;
377 case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
378 case SND_PCM_ACCESS_RW_NONINTERLEAVED:
379 params->info |= SND_PCM_INFO_NONINTERLEAVED;
383 if (io->data->callback->pause)
384 params->info |= SND_PCM_INFO_PAUSE;
385 if (io->data->callback->resume)
386 params->info |= SND_PCM_INFO_RESUME;
389 fprintf(stderr, "XXX\n");
395 static int snd_pcm_ioplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
397 ioplug_priv_t *io = pcm->private_data;
400 INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access);
401 INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format);
402 INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels);
403 INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0);
404 INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0);
405 INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size);
406 if (io->data->callback->hw_params) {
407 err = io->data->callback->hw_params(io->data, params);
410 INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access);
411 INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format);
412 INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels);
413 INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0);
414 INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0);
415 INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size);
420 static int snd_pcm_ioplug_hw_free(snd_pcm_t *pcm)
422 ioplug_priv_t *io = pcm->private_data;
424 if (io->data->callback->hw_free)
425 return io->data->callback->hw_free(io->data);
429 static int snd_pcm_ioplug_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
431 ioplug_priv_t *io = pcm->private_data;
433 if (io->data->callback->sw_params)
434 return io->data->callback->sw_params(io->data, params);
439 static int snd_pcm_ioplug_start(snd_pcm_t *pcm)
441 ioplug_priv_t *io = pcm->private_data;
444 if (io->data->state != SND_PCM_STATE_PREPARED)
447 err = io->data->callback->start(io->data);
451 gettimestamp(&io->trigger_tstamp, pcm->monotonic);
452 io->data->state = SND_PCM_STATE_RUNNING;
457 static int snd_pcm_ioplug_drop(snd_pcm_t *pcm)
459 ioplug_priv_t *io = pcm->private_data;
461 if (io->data->state == SND_PCM_STATE_OPEN)
464 io->data->callback->stop(io->data);
466 gettimestamp(&io->trigger_tstamp, pcm->monotonic);
467 io->data->state = SND_PCM_STATE_SETUP;
472 static int snd_pcm_ioplug_drain(snd_pcm_t *pcm)
474 ioplug_priv_t *io = pcm->private_data;
476 if (io->data->state == SND_PCM_STATE_OPEN)
478 if (io->data->callback->drain)
479 io->data->callback->drain(io->data);
480 return snd_pcm_ioplug_drop(pcm);
483 static int snd_pcm_ioplug_pause(snd_pcm_t *pcm, int enable)
485 ioplug_priv_t *io = pcm->private_data;
486 static const snd_pcm_state_t states[2] = {
487 SND_PCM_STATE_RUNNING, SND_PCM_STATE_PAUSED
493 if (io->data->state != states[prev])
495 if (io->data->callback->pause) {
496 err = io->data->callback->pause(io->data, enable);
500 io->data->state = states[enable];
504 static snd_pcm_sframes_t snd_pcm_ioplug_rewindable(snd_pcm_t *pcm)
506 return snd_pcm_mmap_hw_avail(pcm);
509 static snd_pcm_sframes_t snd_pcm_ioplug_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
511 snd_pcm_mmap_appl_backward(pcm, frames);
515 static snd_pcm_sframes_t snd_pcm_ioplug_forwardable(snd_pcm_t *pcm)
517 return snd_pcm_mmap_avail(pcm);
520 static snd_pcm_sframes_t snd_pcm_ioplug_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
522 snd_pcm_mmap_appl_forward(pcm, frames);
526 static int snd_pcm_ioplug_resume(snd_pcm_t *pcm)
528 ioplug_priv_t *io = pcm->private_data;
530 if (io->data->callback->resume)
531 io->data->callback->resume(io->data);
535 static snd_pcm_sframes_t ioplug_priv_transfer_areas(snd_pcm_t *pcm,
536 const snd_pcm_channel_area_t *areas,
537 snd_pcm_uframes_t offset,
538 snd_pcm_uframes_t size)
540 ioplug_priv_t *io = pcm->private_data;
541 snd_pcm_sframes_t result;
545 if (io->data->callback->transfer)
546 result = io->data->callback->transfer(io->data, areas, offset, size);
550 snd_pcm_mmap_appl_forward(pcm, result);
554 static snd_pcm_sframes_t snd_pcm_ioplug_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
557 return snd_pcm_mmap_writei(pcm, buffer, size);
559 snd_pcm_channel_area_t areas[pcm->channels];
560 snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
561 return snd_pcm_write_areas(pcm, areas, 0, size,
562 ioplug_priv_transfer_areas);
566 static snd_pcm_sframes_t snd_pcm_ioplug_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
569 return snd_pcm_mmap_writen(pcm, bufs, size);
571 snd_pcm_channel_area_t areas[pcm->channels];
572 snd_pcm_areas_from_bufs(pcm, areas, bufs);
573 return snd_pcm_write_areas(pcm, areas, 0, size,
574 ioplug_priv_transfer_areas);
578 static snd_pcm_sframes_t snd_pcm_ioplug_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
581 return snd_pcm_mmap_readi(pcm, buffer, size);
583 snd_pcm_channel_area_t areas[pcm->channels];
584 snd_pcm_areas_from_buf(pcm, areas, buffer);
585 return snd_pcm_read_areas(pcm, areas, 0, size,
586 ioplug_priv_transfer_areas);
590 static snd_pcm_sframes_t snd_pcm_ioplug_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
593 return snd_pcm_mmap_readn(pcm, bufs, size);
595 snd_pcm_channel_area_t areas[pcm->channels];
596 snd_pcm_areas_from_bufs(pcm, areas, bufs);
597 return snd_pcm_read_areas(pcm, areas, 0, size,
598 ioplug_priv_transfer_areas);
602 static snd_pcm_sframes_t snd_pcm_ioplug_mmap_commit(snd_pcm_t *pcm,
603 snd_pcm_uframes_t offset,
604 snd_pcm_uframes_t size)
606 if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
607 pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
608 pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
609 const snd_pcm_channel_area_t *areas;
610 snd_pcm_uframes_t ofs, frames = size;
612 snd_pcm_mmap_begin(pcm, &areas, &ofs, &frames);
615 return ioplug_priv_transfer_areas(pcm, areas, offset, frames);
618 snd_pcm_mmap_appl_forward(pcm, size);
622 static snd_pcm_sframes_t snd_pcm_ioplug_avail_update(snd_pcm_t *pcm)
624 ioplug_priv_t *io = pcm->private_data;
625 snd_pcm_uframes_t avail;
627 snd_pcm_ioplug_hw_ptr_update(pcm);
628 if (io->data->state == SNDRV_PCM_STATE_XRUN)
630 if (pcm->stream == SND_PCM_STREAM_CAPTURE &&
631 pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
632 pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
633 if (io->data->callback->transfer) {
634 const snd_pcm_channel_area_t *areas;
635 snd_pcm_uframes_t offset, size = UINT_MAX;
636 snd_pcm_sframes_t result;
638 snd_pcm_mmap_begin(pcm, &areas, &offset, &size);
639 result = io->data->callback->transfer(io->data, areas, offset, size);
644 avail = snd_pcm_mmap_avail(pcm);
645 if (avail > io->avail_max)
646 io->avail_max = avail;
647 return (snd_pcm_sframes_t)avail;
650 static int snd_pcm_ioplug_nonblock(snd_pcm_t *pcm, int nonblock)
652 ioplug_priv_t *io = pcm->private_data;
654 io->data->nonblock = nonblock;
658 static int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm)
660 ioplug_priv_t *io = pcm->private_data;
662 if (io->data->callback->poll_descriptors_count)
663 return io->data->callback->poll_descriptors_count(io->data);
668 static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
670 ioplug_priv_t *io = pcm->private_data;
672 if (io->data->callback->poll_descriptors)
673 return io->data->callback->poll_descriptors(io->data, pfds, space);
674 if (pcm->poll_fd < 0)
676 if (space >= 1 && pfds) {
677 pfds->fd = pcm->poll_fd;
678 pfds->events = pcm->poll_events | POLLERR | POLLNVAL;
685 static int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
687 ioplug_priv_t *io = pcm->private_data;
689 if (io->data->callback->poll_revents)
690 return io->data->callback->poll_revents(io->data, pfds, nfds, revents);
692 *revents = pfds->revents;
696 static int snd_pcm_ioplug_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
701 static int snd_pcm_ioplug_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
702 int sig ATTRIBUTE_UNUSED,
703 pid_t pid ATTRIBUTE_UNUSED)
708 static int snd_pcm_ioplug_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
713 static void snd_pcm_ioplug_dump(snd_pcm_t *pcm, snd_output_t *out)
715 ioplug_priv_t *io = pcm->private_data;
717 if (io->data->callback->dump)
718 io->data->callback->dump(io->data, out);
721 snd_output_printf(out, "%s\n", io->data->name);
723 snd_output_printf(out, "IO-PCM Plugin\n");
725 snd_output_printf(out, "Its setup is:\n");
726 snd_pcm_dump_setup(pcm, out);
731 static void clear_io_params(ioplug_priv_t *io)
734 for (i = 0; i < SND_PCM_IOPLUG_HW_PARAMS; i++)
735 snd_ext_parm_clear(&io->params[i]);
738 static int snd_pcm_ioplug_close(snd_pcm_t *pcm)
740 ioplug_priv_t *io = pcm->private_data;
743 if (io->data->callback->close)
744 io->data->callback->close(io->data);
750 static const snd_pcm_ops_t snd_pcm_ioplug_ops = {
751 .close = snd_pcm_ioplug_close,
752 .nonblock = snd_pcm_ioplug_nonblock,
753 .async = snd_pcm_ioplug_async,
754 .info = snd_pcm_ioplug_info,
755 .hw_refine = snd_pcm_ioplug_hw_refine,
756 .hw_params = snd_pcm_ioplug_hw_params,
757 .hw_free = snd_pcm_ioplug_hw_free,
758 .sw_params = snd_pcm_ioplug_sw_params,
759 .channel_info = snd_pcm_ioplug_channel_info,
760 .dump = snd_pcm_ioplug_dump,
761 .mmap = snd_pcm_ioplug_mmap,
762 .munmap = snd_pcm_ioplug_munmap,
765 static const snd_pcm_fast_ops_t snd_pcm_ioplug_fast_ops = {
766 .status = snd_pcm_ioplug_status,
767 .prepare = snd_pcm_ioplug_prepare,
768 .reset = snd_pcm_ioplug_reset,
769 .start = snd_pcm_ioplug_start,
770 .drop = snd_pcm_ioplug_drop,
771 .drain = snd_pcm_ioplug_drain,
772 .pause = snd_pcm_ioplug_pause,
773 .state = snd_pcm_ioplug_state,
774 .hwsync = snd_pcm_ioplug_hwsync,
775 .delay = snd_pcm_ioplug_delay,
776 .resume = snd_pcm_ioplug_resume,
780 .rewindable = snd_pcm_ioplug_rewindable,
781 .rewind = snd_pcm_ioplug_rewind,
782 .forwardable = snd_pcm_ioplug_forwardable,
783 .forward = snd_pcm_ioplug_forward,
784 .writei = snd_pcm_ioplug_writei,
785 .writen = snd_pcm_ioplug_writen,
786 .readi = snd_pcm_ioplug_readi,
787 .readn = snd_pcm_ioplug_readn,
788 .avail_update = snd_pcm_ioplug_avail_update,
789 .mmap_commit = snd_pcm_ioplug_mmap_commit,
790 .htimestamp = snd_pcm_generic_real_htimestamp,
791 .poll_descriptors_count = snd_pcm_ioplug_poll_descriptors_count,
792 .poll_descriptors = snd_pcm_ioplug_poll_descriptors,
793 .poll_revents = snd_pcm_ioplug_poll_revents,
796 #endif /* !DOC_HIDDEN */
802 /*! \page pcm_external_plugins PCM External Plugin SDK
804 \section pcm_ioplug External Plugin: I/O Plugin
806 The I/O-type plugin is a PCM plugin to work as the input or output terminal point,
807 i.e. as a user-space PCM driver.
809 The new plugin is created via #snd_pcm_ioplug_create() function.
810 The first argument is a pointer of the pluging information. Some of
811 this struct must be initialized in prior to call
812 #snd_pcm_ioplug_create(). Then the function fills other fields in
813 return. The rest arguments, name, stream and mode, are usually
814 identical with the values passed from the ALSA plugin constructor.
816 The following fields are mandatory: version, name, callback.
817 Otherfields are optional and should be initialized with zero.
819 The constant #SND_PCM_IOPLUG_VERSION must be passed to the version
820 field for the version check in alsa-lib. A non-NULL ASCII string
821 has to be passed to the name field. The callback field contains the
822 table of callback functions for this plugin (defined as
823 #snd_pcm_ioplug_callback_t).
825 flags field specifies the optional bit-flags. poll_fd and poll_events
826 specify the poll file descriptor and the corresponding poll events
827 (POLLIN, POLLOUT) for the plugin. If the plugin requires multiple
828 poll descriptors or poll descriptor(s) dynamically varying, set
829 poll_descriptors and poll_descriptors_count callbacks to the callback
830 table. Then the poll_fd and poll_events field are ignored.
832 mmap_rw specifies whether the plugin behaves in the pseudo mmap mode.
833 When this value is set to 1, the plugin creates always a local buffer
834 and performs read/write calls using this buffer as if it's mmapped.
835 The address of local buffer can be obtained via
836 #snd_pcm_ioplug_mmap_areas() function.
837 When poll_fd, poll_events and mmap_rw fields are changed after
838 #snd_pcm_ioplug_create(), call #snd_pcm_ioplug_reinit_status() to
841 The driver can set an arbitrary value (pointer) to private_data
842 field to refer its own data in the callbacks.
844 The rest fields are filled by #snd_pcm_ioplug_create(). The pcm field
845 is the resultant PCM handle. The others are the current status of the
848 The callback functions in #snd_pcm_ioplug_callback_t define the real
849 behavior of the driver.
850 At least, start, stop and pointer callbacks must be given. Other
851 callbacks are optional. The start and stop callbacks are called when
852 the PCM stream is started and stopped, repsectively. The pointer
853 callback returns the current DMA position, which may be called at any
856 The transfer callback is called when any data transfer happens. It
857 receives the area array, offset and the size to transfer. The area
858 array contains the array of snd_pcm_channel_area_t with the elements
859 of number of channels.
861 When the PCM is closed, close callback is called. If the driver
862 allocates any internal buffers, they should be released in this
863 callback. The hw_params and hw_free callbacks are called when
864 hw_params are set and reset, respectively. Note that they may be
865 called multiple times according to the application. Similarly,
866 sw_params callback is called when sw_params is set or changed.
868 The prepare, drain, pause and resume callbacks are called when
869 #snd_pcm_prepare(), #snd_pcm_drain(), #snd_pcm_pause(), and
870 #snd_pcm_resume() are called. The poll_descriptors_count and
871 poll_descriptors callbacks are used to return the multiple or dynamic
872 poll descriptors as mentioned above. The poll_revents callback is
873 used to modify poll events. If the driver needs to mangle the native
874 poll events to proper poll events for PCM, you can do it in this
877 Finally, the dump callback is used to print the status of the plugin.
879 The hw_params constraints can be defined via either
880 #snd_pcm_ioplug_set_param_minmax() and #snd_pcm_ioplug_set_param_list()
881 functions after calling #snd_pcm_ioplug_create().
882 The former defines the minimal and maximal acceptable values for the
883 given hw_params parameter (SND_PCM_IOPLUG_HW_XXX).
884 This function can't be used for the format parameter. The latter
885 function specifies the available parameter values as the list.
887 To clear the parameter constraints, call #snd_pcm_ioplug_params_reset() function.
892 * \brief Create an ioplug instance
893 * \param ioplug the ioplug handle
894 * \param name name of PCM
895 * \param stream stream direction
896 * \param mode PCM open mode
897 * \return 0 if successful, or a negative error code
899 * Creates the ioplug instance.
901 * The callback is the mandatory field of ioplug handle. At least, start, stop and
902 * pointer callbacks must be set before calling this function.
905 int snd_pcm_ioplug_create(snd_pcm_ioplug_t *ioplug, const char *name,
906 snd_pcm_stream_t stream, int mode)
912 assert(ioplug && ioplug->callback);
913 assert(ioplug->callback->start &&
914 ioplug->callback->stop &&
915 ioplug->callback->pointer);
917 /* We support 1.0.0 to current */
918 if (ioplug->version < 0x010000 ||
919 ioplug->version > SND_PCM_IOPLUG_VERSION) {
920 SNDERR("ioplug: Plugin version mismatch\n");
924 io = calloc(1, sizeof(*io));
929 ioplug->state = SND_PCM_STATE_OPEN;
930 ioplug->stream = stream;
932 err = snd_pcm_new(&pcm, SND_PCM_TYPE_IOPLUG, name, stream, mode);
939 pcm->ops = &snd_pcm_ioplug_ops;
940 pcm->fast_ops = &snd_pcm_ioplug_fast_ops;
941 pcm->private_data = io;
943 snd_pcm_set_hw_ptr(pcm, &ioplug->hw_ptr, -1, 0);
944 snd_pcm_set_appl_ptr(pcm, &ioplug->appl_ptr, -1, 0);
946 snd_pcm_ioplug_reinit_status(ioplug);
952 * \brief Delete the ioplug instance
953 * \param ioplug the ioplug handle
954 * \return 0 if successful, or a negative error code
956 int snd_pcm_ioplug_delete(snd_pcm_ioplug_t *ioplug)
958 return snd_pcm_close(ioplug->pcm);
963 * \brief Reset ioplug parameters
964 * \param ioplug the ioplug handle
966 * Resets the all parameters for the given ioplug handle.
968 void snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t *ioplug)
970 ioplug_priv_t *io = ioplug->pcm->private_data;
975 * \brief Set parameter as the list
976 * \param ioplug the ioplug handle
977 * \param type parameter type
978 * \param num_list number of available values
979 * \param list the list of available values
980 * \return 0 if successful, or a negative error code
982 * Sets the parameter as the list.
983 * The available values of the given parameter type is restricted to the ones of the given list.
985 int snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t *ioplug, int type, unsigned int num_list, const unsigned int *list)
987 ioplug_priv_t *io = ioplug->pcm->private_data;
988 if (type < 0 && type >= SND_PCM_IOPLUG_HW_PARAMS) {
989 SNDERR("IOPLUG: invalid parameter type %d", type);
992 if (type == SND_PCM_IOPLUG_HW_PERIODS)
993 io->params[type].integer = 1;
994 return snd_ext_parm_set_list(&io->params[type], num_list, list);
998 * \brief Set parameter as the min/max values
999 * \param ioplug the ioplug handle
1000 * \param type parameter type
1001 * \param min the minimum value
1002 * \param max the maximum value
1003 * \return 0 if successful, or a negative error code
1005 * Sets the parameter as the min/max values.
1006 * The available values of the given parameter type is restricted between the given
1007 * minimum and maximum values.
1009 int snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *ioplug, int type, unsigned int min, unsigned int max)
1011 ioplug_priv_t *io = ioplug->pcm->private_data;
1012 if (type < 0 && type >= SND_PCM_IOPLUG_HW_PARAMS) {
1013 SNDERR("IOPLUG: invalid parameter type %d", type);
1016 if (type == SND_PCM_IOPLUG_HW_ACCESS || type == SND_PCM_IOPLUG_HW_FORMAT) {
1017 SNDERR("IOPLUG: invalid parameter type %d", type);
1020 if (type == SND_PCM_IOPLUG_HW_PERIODS)
1021 io->params[type].integer = 1;
1022 return snd_ext_parm_set_minmax(&io->params[type], min, max);
1026 * \brief Reinitialize the poll and mmap status
1027 * \param ioplug the ioplug handle
1028 * \return 0 if successful, or a negative error code
1030 * Reinitializes the poll and the mmap status of the PCM.
1031 * Call this function to propagate the status change in the ioplug instance to
1032 * its PCM internals.
1034 int snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug)
1036 ioplug->pcm->poll_fd = ioplug->poll_fd;
1037 ioplug->pcm->poll_events = ioplug->poll_events;
1038 ioplug->pcm->monotonic = (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC) != 0;
1039 ioplug->pcm->mmap_rw = ioplug->mmap_rw;
1044 * \brief Get mmap area of ioplug
1045 * \param ioplug the ioplug handle
1046 * \return the mmap channel areas if available, or NULL
1048 * Returns the mmap channel areas if available. When mmap_rw field is not set,
1049 * this function always returns NULL.
1051 const snd_pcm_channel_area_t *snd_pcm_ioplug_mmap_areas(snd_pcm_ioplug_t *ioplug)
1053 if (ioplug->mmap_rw)
1054 return snd_pcm_mmap_areas(ioplug->pcm);
1059 * \brief Change the ioplug PCM status
1060 * \param ioplug the ioplug handle
1061 * \param state the PCM status
1062 * \return zero if successful or a negative error code
1064 * Changes the PCM status of the ioplug to the given value.
1065 * This function can be used for external plugins to notify the status
1066 * change, e.g. XRUN.
1068 int snd_pcm_ioplug_set_state(snd_pcm_ioplug_t *ioplug, snd_pcm_state_t state)
1070 ioplug->state = state;