1 /**
2 * \file pcm/pcm_ioplug.c
3 * \ingroup Plugin_SDK
4 * \brief I/O Plugin SDK
5 * \author Takashi Iwai <tiwai@suse.de>
6 * \date 2005
7 */
8 /*
9 * PCM - External I/O Plugin SDK
10 * Copyright (c) 2005 by Takashi Iwai <tiwai@suse.de>
11 *
12 *
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.
17 *
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.
22 *
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
26 *
27 */
28
29 #include "pcm_local.h"
30 #include "pcm_ioplug.h"
31 #include "pcm_ext_parm.h"
32 #include "pcm_generic.h"
33
34 #ifndef PIC
35 /* entry for static linking */
36 const char *_snd_module_pcm_ioplug = "";
37 #endif
38
39 #ifndef DOC_HIDDEN
40
41 /* hw_params */
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;
48 } ioplug_priv_t;
49
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);
54
55 /* update the hw pointer */
56 /* called in lock */
snd_pcm_ioplug_hw_ptr_update(snd_pcm_t * pcm)57 static void snd_pcm_ioplug_hw_ptr_update(snd_pcm_t *pcm)
58 {
59 ioplug_priv_t *io = pcm->private_data;
60 snd_pcm_sframes_t hw;
61
62 hw = io->data->callback->pointer(io->data);
63 if (hw >= 0) {
64 snd_pcm_uframes_t delta;
65 snd_pcm_uframes_t avail;
66
67 if ((snd_pcm_uframes_t)hw >= io->last_hw)
68 delta = hw - io->last_hw;
69 else {
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;
74 }
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);
81 }
82 io->last_hw = (snd_pcm_uframes_t)hw;
83 } else {
84 if (io->data->state == SND_PCM_STATE_DRAINING)
85 snd_pcm_ioplug_drop(pcm);
86 else
87 io->data->state = SNDRV_PCM_STATE_XRUN;
88 }
89 }
90
snd_pcm_ioplug_info(snd_pcm_t * pcm,snd_pcm_info_t * info)91 static int snd_pcm_ioplug_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
92 {
93 memset(info, 0, sizeof(*info));
94 info->stream = pcm->stream;
95 info->card = -1;
96 if (pcm->name) {
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));
100 }
101 info->subdevices_count = 1;
102 return 0;
103 }
104
snd_pcm_ioplug_channel_info(snd_pcm_t * pcm,snd_pcm_channel_info_t * info)105 static int snd_pcm_ioplug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
106 {
107 return snd_pcm_channel_info_shm(pcm, info, -1);
108 }
109
snd_pcm_ioplug_delay(snd_pcm_t * pcm,snd_pcm_sframes_t * delayp)110 static int snd_pcm_ioplug_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
111 {
112 ioplug_priv_t *io = pcm->private_data;
113
114 if (io->data->version >= 0x010001 &&
115 io->data->callback->delay)
116 return io->data->callback->delay(io->data, delayp);
117 else {
118 snd_pcm_ioplug_hw_ptr_update(pcm);
119 *delayp = snd_pcm_mmap_delay(pcm);
120 }
121 return 0;
122 }
123
snd_pcm_ioplug_status(snd_pcm_t * pcm,snd_pcm_status_t * status)124 static int snd_pcm_ioplug_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
125 {
126 ioplug_priv_t *io = pcm->private_data;
127 snd_pcm_sframes_t sd;
128
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);
140 status->delay = sd;
141 return 0;
142 }
143
snd_pcm_ioplug_state(snd_pcm_t * pcm)144 static snd_pcm_state_t snd_pcm_ioplug_state(snd_pcm_t *pcm)
145 {
146 ioplug_priv_t *io = pcm->private_data;
147 return io->data->state;
148 }
149
snd_pcm_ioplug_hwsync(snd_pcm_t * pcm)150 static int snd_pcm_ioplug_hwsync(snd_pcm_t *pcm)
151 {
152 snd_pcm_ioplug_hw_ptr_update(pcm);
153 return 0;
154 }
155
snd_pcm_ioplug_reset(snd_pcm_t * pcm)156 static int snd_pcm_ioplug_reset(snd_pcm_t *pcm)
157 {
158 ioplug_priv_t *io = pcm->private_data;
159
160 io->data->appl_ptr = 0;
161 io->data->hw_ptr = 0;
162 io->last_hw = 0;
163 io->avail_max = 0;
164 return 0;
165 }
166
snd_pcm_ioplug_prepare(snd_pcm_t * pcm)167 static int snd_pcm_ioplug_prepare(snd_pcm_t *pcm)
168 {
169 ioplug_priv_t *io = pcm->private_data;
170 int err = 0;
171
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);
176 snd_pcm_lock(pcm);
177 }
178 if (err < 0)
179 return err;
180
181 io->data->state = SND_PCM_STATE_PREPARED;
182 return err;
183 }
184
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,
193 };
194
195 /* x = a * b */
rule_mul(snd_pcm_hw_params_t * params,int x,int a,int b)196 static int rule_mul(snd_pcm_hw_params_t *params, int x, int a, int b)
197 {
198 snd_interval_t t;
199
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);
203 }
204
205 /* x = a / b */
rule_div(snd_pcm_hw_params_t * params,int x,int a,int b)206 static int rule_div(snd_pcm_hw_params_t *params, int x, int a, int b)
207 {
208 snd_interval_t t;
209
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);
213 }
214
215 /* x = a * b / k */
rule_muldivk(snd_pcm_hw_params_t * params,int x,int a,int b,int k)216 static int rule_muldivk(snd_pcm_hw_params_t *params, int x, int a, int b, int k)
217 {
218 snd_interval_t t;
219
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);
223 }
224
225 /* x = a * k / b */
rule_mulkdiv(snd_pcm_hw_params_t * params,int x,int a,int k,int b)226 static int rule_mulkdiv(snd_pcm_hw_params_t *params, int x, int a, int k, int b)
227 {
228 snd_interval_t t;
229
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);
233 }
234
235 #if 0
236 static void dump_parm(snd_pcm_hw_params_t *params)
237 {
238 snd_output_t *log;
239 snd_output_stdio_attach(&log, stderr, 0);
240 snd_pcm_hw_params_dump(params, log);
241 snd_output_close(log);
242 }
243 #endif
244
245 /* refine *_TIME and *_SIZE, then update *_BYTES */
refine_time_and_size(snd_pcm_hw_params_t * params,int time,int size,int bytes)246 static int refine_time_and_size(snd_pcm_hw_params_t *params,
247 int time, int size, int bytes)
248 {
249 int err, change1 = 0;
250
251 /* size = time * rate / 1000000 */
252 err = rule_muldivk(params, size, time,
253 SND_PCM_HW_PARAM_RATE, 1000000);
254 if (err < 0)
255 return err;
256 change1 |= err;
257
258 /* bytes = size * framebits / 8 */
259 err = rule_muldivk(params, bytes, size,
260 SND_PCM_HW_PARAM_FRAME_BITS, 8);
261 if (err < 0)
262 return err;
263 change1 |= err;
264 return change1;
265 }
266
267 /* refine *_TIME and *_SIZE from *_BYTES */
refine_back_time_and_size(snd_pcm_hw_params_t * params,int time,int size,int bytes)268 static int refine_back_time_and_size(snd_pcm_hw_params_t *params,
269 int time, int size, int bytes)
270 {
271 int err;
272
273 /* size = bytes * 8 / framebits */
274 err = rule_mulkdiv(params, size, bytes, 8, SND_PCM_HW_PARAM_FRAME_BITS);
275 if (err < 0)
276 return err;
277 /* time = size * 1000000 / rate */
278 err = rule_mulkdiv(params, time, size, 1000000, SND_PCM_HW_PARAM_RATE);
279 if (err < 0)
280 return err;
281 return 0;
282 }
283
284
snd_pcm_ioplug_hw_refine(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)285 static int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
286 {
287 int change = 0, change1, change2, err;
288 ioplug_priv_t *io = pcm->private_data;
289 struct snd_ext_parm *p;
290 unsigned int i;
291
292 /* access, format */
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]),
295 io->params, i);
296 if (err < 0)
297 return err;
298 change |= err;
299 }
300 /* channels, rate */
301 for (; i <= SND_PCM_IOPLUG_HW_RATE; i++) {
302 err = snd_ext_parm_interval_refine(hw_param_interval(params, hw_params_type[i]),
303 io->params, i);
304 if (err < 0)
305 return err;
306 change |= err;
307 }
308
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);
315 if (err < 0)
316 return err;
317 change |= err;
318 }
319
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);
323 if (change1 < 0)
324 return change1;
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);
327 if (err < 0)
328 return err;
329 change1 |= err;
330 if (change1) {
331 change |= change1;
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);
335 if (err < 0)
336 return err;
337 }
338
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);
342 if (change1 < 0)
343 return change1;
344 change |= change1;
345
346 do {
347 change2 = 0;
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);
350 if (err < 0)
351 return err;
352 change2 |= err;
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);
357 if (err < 0)
358 return err;
359 change2 |= err;
360 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIODS),
361 io->params, SND_PCM_IOPLUG_HW_PERIODS);
362 if (err < 0)
363 return err;
364 change2 |= err;
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);
369 if (err < 0)
370 return err;
371 change2 |= err;
372 change1 |= change2;
373 } while (change2);
374 change |= change1;
375
376 if (change1) {
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);
380 if (err < 0)
381 return err;
382 }
383
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);
388 if (err < 0)
389 return err;
390 if (err) {
391 /* update period_size and period_time */
392 change |= err;
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);
395 if (err < 0)
396 return err;
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);
400 if (err < 0)
401 return err;
402 }
403
404 params->info = SND_PCM_INFO_BLOCK_TRANSFER;
405 p = &io->params[SND_PCM_IOPLUG_HW_ACCESS];
406 if (p->active) {
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;
412 break;
413 case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
414 case SND_PCM_ACCESS_RW_NONINTERLEAVED:
415 params->info |= SND_PCM_INFO_NONINTERLEAVED;
416 break;
417 }
418 }
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;
423
424 #if 0
425 fprintf(stderr, "XXX\n");
426 dump_parm(params);
427 #endif
428 return change;
429 }
430
snd_pcm_ioplug_hw_params(snd_pcm_t * pcm,snd_pcm_hw_params_t * params)431 static int snd_pcm_ioplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
432 {
433 ioplug_priv_t *io = pcm->private_data;
434 int err;
435
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);
444 if (err < 0)
445 return err;
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);
452 }
453 return 0;
454 }
455
snd_pcm_ioplug_hw_free(snd_pcm_t * pcm)456 static int snd_pcm_ioplug_hw_free(snd_pcm_t *pcm)
457 {
458 ioplug_priv_t *io = pcm->private_data;
459
460 if (io->data->callback->hw_free)
461 return io->data->callback->hw_free(io->data);
462 return 0;
463 }
464
snd_pcm_ioplug_sw_params(snd_pcm_t * pcm,snd_pcm_sw_params_t * params)465 static int snd_pcm_ioplug_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
466 {
467 ioplug_priv_t *io = pcm->private_data;
468 int err;
469
470 if (!io->data->callback->sw_params)
471 return 0;
472
473 snd_pcm_unlock(pcm); /* to avoid deadlock */
474 err = io->data->callback->sw_params(io->data, params);
475 snd_pcm_lock(pcm);
476
477 return err;
478 }
479
480
snd_pcm_ioplug_start(snd_pcm_t * pcm)481 static int snd_pcm_ioplug_start(snd_pcm_t *pcm)
482 {
483 ioplug_priv_t *io = pcm->private_data;
484 int err;
485
486 if (io->data->state != SND_PCM_STATE_PREPARED)
487 return -EBADFD;
488
489 err = io->data->callback->start(io->data);
490 if (err < 0)
491 return err;
492
493 gettimestamp(&io->trigger_tstamp, pcm->tstamp_type);
494 io->data->state = SND_PCM_STATE_RUNNING;
495
496 return 0;
497 }
498
snd_pcm_ioplug_drop(snd_pcm_t * pcm)499 static int snd_pcm_ioplug_drop(snd_pcm_t *pcm)
500 {
501 ioplug_priv_t *io = pcm->private_data;
502
503 if (io->data->state == SND_PCM_STATE_OPEN)
504 return -EBADFD;
505
506 io->data->callback->stop(io->data);
507
508 gettimestamp(&io->trigger_tstamp, pcm->tstamp_type);
509 io->data->state = SND_PCM_STATE_SETUP;
510
511 return 0;
512 }
513
ioplug_drain_via_poll(snd_pcm_t * pcm)514 static int ioplug_drain_via_poll(snd_pcm_t *pcm)
515 {
516 ioplug_priv_t *io = pcm->private_data;
517
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)
521 break;
522 /* in non-blocking mode, let application to poll() by itself */
523 if (io->data->nonblock)
524 return -EAGAIN;
525 if (snd_pcm_wait_nocheck(pcm, -1) < 0)
526 break;
527 }
528
529 return 0; /* force to drop at error */
530 }
531
532 /* need own locking */
snd_pcm_ioplug_drain(snd_pcm_t * pcm)533 static int snd_pcm_ioplug_drain(snd_pcm_t *pcm)
534 {
535 ioplug_priv_t *io = pcm->private_data;
536 int err = 0;
537
538 snd_pcm_lock(pcm);
539 switch (io->data->state) {
540 case SND_PCM_STATE_OPEN:
541 case SND_PCM_STATE_DISCONNECTED:
542 case SND_PCM_STATE_SUSPENDED:
543 snd_pcm_unlock(pcm);
544 return -EBADFD;
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);
549 if (err < 0)
550 goto unlock;
551 }
552 io->data->state = SND_PCM_STATE_DRAINING;
553 }
554 break;
555 case SND_PCM_STATE_RUNNING:
556 io->data->state = SND_PCM_STATE_DRAINING;
557 break;
558 default:
559 break;
560 }
561
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);
566 snd_pcm_lock(pcm);
567 } else {
568 err = ioplug_drain_via_poll(pcm);
569 }
570 }
571
572 unlock:
573 if (!err && io->data->state != SND_PCM_STATE_SETUP)
574 snd_pcm_ioplug_drop(pcm);
575 snd_pcm_unlock(pcm);
576 return err;
577 }
578
snd_pcm_ioplug_pause(snd_pcm_t * pcm,int enable)579 static int snd_pcm_ioplug_pause(snd_pcm_t *pcm, int enable)
580 {
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
584 };
585 int prev, err;
586
587 prev = !enable;
588 enable = !prev;
589 if (io->data->state != states[prev])
590 return -EBADFD;
591 if (io->data->callback->pause) {
592 err = io->data->callback->pause(io->data, enable);
593 if (err < 0)
594 return err;
595 }
596 io->data->state = states[enable];
597 return 0;
598 }
599
snd_pcm_ioplug_rewindable(snd_pcm_t * pcm)600 static snd_pcm_sframes_t snd_pcm_ioplug_rewindable(snd_pcm_t *pcm)
601 {
602 return snd_pcm_mmap_hw_rewindable(pcm);
603 }
604
snd_pcm_ioplug_rewind(snd_pcm_t * pcm,snd_pcm_uframes_t frames)605 static snd_pcm_sframes_t snd_pcm_ioplug_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
606 {
607 snd_pcm_mmap_appl_backward(pcm, frames);
608 return frames;
609 }
610
snd_pcm_ioplug_forwardable(snd_pcm_t * pcm)611 static snd_pcm_sframes_t snd_pcm_ioplug_forwardable(snd_pcm_t *pcm)
612 {
613 return snd_pcm_mmap_avail(pcm);
614 }
615
snd_pcm_ioplug_forward(snd_pcm_t * pcm,snd_pcm_uframes_t frames)616 static snd_pcm_sframes_t snd_pcm_ioplug_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
617 {
618 snd_pcm_mmap_appl_forward(pcm, frames);
619 return frames;
620 }
621
622 /* need own locking */
snd_pcm_ioplug_resume(snd_pcm_t * pcm)623 static int snd_pcm_ioplug_resume(snd_pcm_t *pcm)
624 {
625 ioplug_priv_t *io = pcm->private_data;
626
627 if (io->data->callback->resume)
628 io->data->callback->resume(io->data);
629 return 0;
630 }
631
632 /* called in lock */
ioplug_priv_transfer_areas(snd_pcm_t * pcm,const snd_pcm_channel_area_t * areas,snd_pcm_uframes_t offset,snd_pcm_uframes_t size)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)
637 {
638 ioplug_priv_t *io = pcm->private_data;
639 snd_pcm_sframes_t result;
640
641 if (! size)
642 return 0;
643 if (io->data->callback->transfer)
644 result = io->data->callback->transfer(io->data, areas, offset, size);
645 else
646 result = size;
647 if (result > 0)
648 snd_pcm_mmap_appl_forward(pcm, result);
649 return result;
650 }
651
snd_pcm_ioplug_writei(snd_pcm_t * pcm,const void * buffer,snd_pcm_uframes_t size)652 static snd_pcm_sframes_t snd_pcm_ioplug_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
653 {
654 if (pcm->mmap_rw)
655 return snd_pcm_mmap_writei(pcm, buffer, size);
656 else {
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);
661 }
662 }
663
snd_pcm_ioplug_writen(snd_pcm_t * pcm,void ** bufs,snd_pcm_uframes_t size)664 static snd_pcm_sframes_t snd_pcm_ioplug_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
665 {
666 if (pcm->mmap_rw)
667 return snd_pcm_mmap_writen(pcm, bufs, size);
668 else {
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);
673 }
674 }
675
snd_pcm_ioplug_readi(snd_pcm_t * pcm,void * buffer,snd_pcm_uframes_t size)676 static snd_pcm_sframes_t snd_pcm_ioplug_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
677 {
678 if (pcm->mmap_rw)
679 return snd_pcm_mmap_readi(pcm, buffer, size);
680 else {
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);
685 }
686 }
687
snd_pcm_ioplug_readn(snd_pcm_t * pcm,void ** bufs,snd_pcm_uframes_t size)688 static snd_pcm_sframes_t snd_pcm_ioplug_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
689 {
690 if (pcm->mmap_rw)
691 return snd_pcm_mmap_readn(pcm, bufs, size);
692 else {
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);
697 }
698 }
699
snd_pcm_ioplug_mmap_begin_capture(snd_pcm_t * pcm,const snd_pcm_channel_area_t ** areas,snd_pcm_uframes_t * offset,snd_pcm_uframes_t * frames)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)
704 {
705 ioplug_priv_t *io = pcm->private_data;
706 int err;
707
708 err = __snd_pcm_mmap_begin_generic(pcm, areas, offset, frames);
709 if (err < 0)
710 return err;
711
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);
717 if (result < 0)
718 return result;
719 }
720
721 return err;
722 }
723
snd_pcm_ioplug_mmap_begin(snd_pcm_t * pcm,const snd_pcm_channel_area_t ** areas,snd_pcm_uframes_t * offset,snd_pcm_uframes_t * 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)
726 {
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);
730 }
731
snd_pcm_ioplug_mmap_commit(snd_pcm_t * pcm,snd_pcm_uframes_t offset,snd_pcm_uframes_t size)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)
735 {
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;
741
742 __snd_pcm_mmap_begin_generic(pcm, &areas, &ofs, &frames);
743 if (ofs != offset)
744 return -EIO;
745 return ioplug_priv_transfer_areas(pcm, areas, offset, frames);
746 }
747
748 snd_pcm_mmap_appl_forward(pcm, size);
749 return size;
750 }
751
snd_pcm_ioplug_avail_update(snd_pcm_t * pcm)752 static snd_pcm_sframes_t snd_pcm_ioplug_avail_update(snd_pcm_t *pcm)
753 {
754 ioplug_priv_t *io = pcm->private_data;
755 snd_pcm_uframes_t avail;
756
757 snd_pcm_ioplug_hw_ptr_update(pcm);
758 if (io->data->state == SND_PCM_STATE_XRUN)
759 return -EPIPE;
760
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;
765 }
766
snd_pcm_ioplug_nonblock(snd_pcm_t * pcm,int nonblock)767 static int snd_pcm_ioplug_nonblock(snd_pcm_t *pcm, int nonblock)
768 {
769 ioplug_priv_t *io = pcm->private_data;
770
771 io->data->nonblock = nonblock;
772 return 0;
773 }
774
snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t * pcm)775 static int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm)
776 {
777 ioplug_priv_t *io = pcm->private_data;
778 int err = 1;
779
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);
783 snd_pcm_lock(pcm);
784 }
785 return err;
786 }
787
snd_pcm_ioplug_poll_descriptors(snd_pcm_t * pcm,struct pollfd * pfds,unsigned int space)788 static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
789 {
790 ioplug_priv_t *io = pcm->private_data;
791 int err;
792
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);
796 snd_pcm_lock(pcm);
797 return err;
798 }
799 if (pcm->poll_fd < 0)
800 return -EIO;
801 if (space >= 1 && pfds) {
802 pfds->fd = pcm->poll_fd;
803 pfds->events = pcm->poll_events | POLLERR | POLLNVAL;
804 } else {
805 return 0;
806 }
807 return 1;
808 }
809
snd_pcm_ioplug_poll_revents(snd_pcm_t * pcm,struct pollfd * pfds,unsigned int nfds,unsigned short * revents)810 static int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
811 {
812 ioplug_priv_t *io = pcm->private_data;
813 int err;
814
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);
818 snd_pcm_lock(pcm);
819 } else {
820 *revents = pfds->revents;
821 err = 0;
822 }
823 return err;
824 }
825
snd_pcm_ioplug_mmap(snd_pcm_t * pcm ATTRIBUTE_UNUSED)826 static int snd_pcm_ioplug_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
827 {
828 return 0;
829 }
830
snd_pcm_ioplug_async(snd_pcm_t * pcm ATTRIBUTE_UNUSED,int sig ATTRIBUTE_UNUSED,pid_t pid 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)
834 {
835 return -ENOSYS;
836 }
837
snd_pcm_ioplug_munmap(snd_pcm_t * pcm ATTRIBUTE_UNUSED)838 static int snd_pcm_ioplug_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
839 {
840 return 0;
841 }
842
snd_pcm_ioplug_query_chmaps(snd_pcm_t * pcm)843 static snd_pcm_chmap_query_t **snd_pcm_ioplug_query_chmaps(snd_pcm_t *pcm)
844 {
845 ioplug_priv_t *io = pcm->private_data;
846
847 if (io->data->version >= 0x010002 &&
848 io->data->callback->query_chmaps)
849 return io->data->callback->query_chmaps(io->data);
850 return NULL;
851 }
852
snd_pcm_ioplug_get_chmap(snd_pcm_t * pcm)853 static snd_pcm_chmap_t *snd_pcm_ioplug_get_chmap(snd_pcm_t *pcm)
854 {
855 ioplug_priv_t *io = pcm->private_data;
856
857 if (io->data->version >= 0x010002 &&
858 io->data->callback->get_chmap)
859 return io->data->callback->get_chmap(io->data);
860 return NULL;
861 }
862
snd_pcm_ioplug_set_chmap(snd_pcm_t * pcm,const snd_pcm_chmap_t * map)863 static int snd_pcm_ioplug_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
864 {
865 ioplug_priv_t *io = pcm->private_data;
866
867 if (io->data->version >= 0x010002 &&
868 io->data->callback->set_chmap)
869 return io->data->callback->set_chmap(io->data, map);
870 return -ENXIO;
871 }
872
snd_pcm_ioplug_dump(snd_pcm_t * pcm,snd_output_t * out)873 static void snd_pcm_ioplug_dump(snd_pcm_t *pcm, snd_output_t *out)
874 {
875 ioplug_priv_t *io = pcm->private_data;
876
877 if (io->data->callback->dump)
878 io->data->callback->dump(io->data, out);
879 else {
880 if (io->data->name)
881 snd_output_printf(out, "%s\n", io->data->name);
882 else
883 snd_output_printf(out, "IO-PCM Plugin\n");
884 if (pcm->setup) {
885 snd_output_printf(out, "Its setup is:\n");
886 snd_pcm_dump_setup(pcm, out);
887 }
888 }
889 }
890
clear_io_params(ioplug_priv_t * io)891 static void clear_io_params(ioplug_priv_t *io)
892 {
893 int i;
894 for (i = 0; i < SND_PCM_IOPLUG_HW_PARAMS; i++)
895 snd_ext_parm_clear(&io->params[i]);
896 }
897
snd_pcm_ioplug_close(snd_pcm_t * pcm)898 static int snd_pcm_ioplug_close(snd_pcm_t *pcm)
899 {
900 ioplug_priv_t *io = pcm->private_data;
901
902 clear_io_params(io);
903 if (io->data->callback->close)
904 io->data->callback->close(io->data);
905 free(io);
906
907 return 0;
908 }
909
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,
926 };
927
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,
940 .link = NULL,
941 .link_slaves = NULL,
942 .unlink = NULL,
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,
958 };
959
960 #endif /* !DOC_HIDDEN */
961
962 /*
963 * Exported functions
964 */
965
966 /*! \page pcm_external_plugins PCM External Plugin SDK
967
968 \section pcm_ioplug External Plugin: I/O Plugin
969
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.
972
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.
979
980 The following fields are mandatory: version, name, callback.
981 Otherfields are optional and should be initialized with zero.
982
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).
988
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.
995
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.
1004
1005 The driver can set an arbitrary value (pointer) to private_data
1006 field to refer its own data in the callbacks.
1007
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
1010 PCM.
1011
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
1018 time.
1019
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.
1024
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.
1031
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
1039 callback.
1040
1041 Finally, the dump callback is used to print the status of the plugin.
1042
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.
1047
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.
1055
1056 To clear the parameter constraints, call #snd_pcm_ioplug_params_reset() function.
1057
1058 */
1059
1060 /**
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
1067 *
1068 * Creates the ioplug instance.
1069 *
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.
1072 *
1073 */
snd_pcm_ioplug_create(snd_pcm_ioplug_t * ioplug,const char * name,snd_pcm_stream_t stream,int mode)1074 int snd_pcm_ioplug_create(snd_pcm_ioplug_t *ioplug, const char *name,
1075 snd_pcm_stream_t stream, int mode)
1076 {
1077 ioplug_priv_t *io;
1078 int err;
1079 snd_pcm_t *pcm;
1080
1081 assert(ioplug && ioplug->callback);
1082 assert(ioplug->callback->start &&
1083 ioplug->callback->stop &&
1084 ioplug->callback->pointer);
1085
1086 /* We support 1.0.0 to current */
1087 if (ioplug->version < 0x010000 ||
1088 ioplug->version > SND_PCM_IOPLUG_VERSION) {
1089 SNDERR("ioplug: Plugin version mismatch: 0x%x\n",
1090 ioplug->version);
1091 return -ENXIO;
1092 }
1093
1094 io = calloc(1, sizeof(*io));
1095 if (! io)
1096 return -ENOMEM;
1097
1098 io->data = ioplug;
1099 ioplug->state = SND_PCM_STATE_OPEN;
1100 ioplug->stream = stream;
1101
1102 err = snd_pcm_new(&pcm, SND_PCM_TYPE_IOPLUG, name, stream, mode);
1103 if (err < 0) {
1104 free(io);
1105 return err;
1106 }
1107
1108 ioplug->pcm = pcm;
1109 pcm->ops = &snd_pcm_ioplug_ops;
1110 pcm->fast_ops = &snd_pcm_ioplug_fast_ops;
1111 pcm->private_data = io;
1112
1113 snd_pcm_set_hw_ptr(pcm, &ioplug->hw_ptr, -1, 0);
1114 snd_pcm_set_appl_ptr(pcm, &ioplug->appl_ptr, -1, 0);
1115
1116 snd_pcm_ioplug_reinit_status(ioplug);
1117
1118 return 0;
1119 }
1120
1121 /**
1122 * \brief Delete the ioplug instance
1123 * \param ioplug the ioplug handle
1124 * \return 0 if successful, or a negative error code
1125 */
snd_pcm_ioplug_delete(snd_pcm_ioplug_t * ioplug)1126 int snd_pcm_ioplug_delete(snd_pcm_ioplug_t *ioplug)
1127 {
1128 return snd_pcm_close(ioplug->pcm);
1129 }
1130
1131
1132 /**
1133 * \brief Reset ioplug parameters
1134 * \param ioplug the ioplug handle
1135 *
1136 * Resets the all parameters for the given ioplug handle.
1137 */
snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t * ioplug)1138 void snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t *ioplug)
1139 {
1140 ioplug_priv_t *io = ioplug->pcm->private_data;
1141 clear_io_params(io);
1142 }
1143
1144 /**
1145 * \brief Set parameter as the list
1146 * \param ioplug the ioplug handle
1147 * \param type parameter type
1148 * \param num_list number of available values
1149 * \param list the list of available values
1150 * \return 0 if successful, or a negative error code
1151 *
1152 * Sets the parameter as the list.
1153 * The available values of the given parameter type is restricted to the ones of the given list.
1154 */
snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t * ioplug,int type,unsigned int num_list,const unsigned int * list)1155 int snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t *ioplug, int type, unsigned int num_list, const unsigned int *list)
1156 {
1157 ioplug_priv_t *io = ioplug->pcm->private_data;
1158 if (type < 0 || type >= SND_PCM_IOPLUG_HW_PARAMS) {
1159 SNDERR("IOPLUG: invalid parameter type %d", type);
1160 return -EINVAL;
1161 }
1162 if (type == SND_PCM_IOPLUG_HW_PERIODS)
1163 io->params[type].integer = 1;
1164 return snd_ext_parm_set_list(&io->params[type], num_list, list);
1165 }
1166
1167 /**
1168 * \brief Set parameter as the min/max values
1169 * \param ioplug the ioplug handle
1170 * \param type parameter type
1171 * \param min the minimum value
1172 * \param max the maximum value
1173 * \return 0 if successful, or a negative error code
1174 *
1175 * Sets the parameter as the min/max values.
1176 * The available values of the given parameter type is restricted between the given
1177 * minimum and maximum values.
1178 */
snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t * ioplug,int type,unsigned int min,unsigned int max)1179 int snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *ioplug, int type, unsigned int min, unsigned int max)
1180 {
1181 ioplug_priv_t *io = ioplug->pcm->private_data;
1182 if (type < 0 || type >= SND_PCM_IOPLUG_HW_PARAMS) {
1183 SNDERR("IOPLUG: invalid parameter type %d", type);
1184 return -EINVAL;
1185 }
1186 if (type == SND_PCM_IOPLUG_HW_ACCESS || type == SND_PCM_IOPLUG_HW_FORMAT) {
1187 SNDERR("IOPLUG: invalid parameter type %d", type);
1188 return -EINVAL;
1189 }
1190 if (type == SND_PCM_IOPLUG_HW_PERIODS)
1191 io->params[type].integer = 1;
1192 return snd_ext_parm_set_minmax(&io->params[type], min, max);
1193 }
1194
1195 /**
1196 * \brief Reinitialize the poll and mmap status
1197 * \param ioplug the ioplug handle
1198 * \return 0 if successful, or a negative error code
1199 *
1200 * Reinitializes the poll and the mmap status of the PCM.
1201 * Call this function to propagate the status change in the ioplug instance to
1202 * its PCM internals.
1203 */
snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t * ioplug)1204 int snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug)
1205 {
1206 ioplug->pcm->poll_fd = ioplug->poll_fd;
1207 ioplug->pcm->poll_events = ioplug->poll_events;
1208 if (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC)
1209 ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC;
1210 else
1211 ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
1212 ioplug->pcm->mmap_rw = ioplug->mmap_rw;
1213 return 0;
1214 }
1215
1216 /**
1217 * \brief Get mmap area of ioplug
1218 * \param ioplug the ioplug handle
1219 * \return the mmap channel areas if available, or NULL
1220 *
1221 * Returns the mmap channel areas if available. When mmap_rw field is not set,
1222 * this function always returns NULL.
1223 */
snd_pcm_ioplug_mmap_areas(snd_pcm_ioplug_t * ioplug)1224 const snd_pcm_channel_area_t *snd_pcm_ioplug_mmap_areas(snd_pcm_ioplug_t *ioplug)
1225 {
1226 if (ioplug->mmap_rw)
1227 return snd_pcm_mmap_areas(ioplug->pcm);
1228 return NULL;
1229 }
1230
1231 /**
1232 * \brief Change the ioplug PCM status
1233 * \param ioplug the ioplug handle
1234 * \param state the PCM status
1235 * \return zero if successful or a negative error code
1236 *
1237 * Changes the PCM status of the ioplug to the given value.
1238 * This function can be used for external plugins to notify the status
1239 * change, e.g. XRUN.
1240 */
snd_pcm_ioplug_set_state(snd_pcm_ioplug_t * ioplug,snd_pcm_state_t state)1241 int snd_pcm_ioplug_set_state(snd_pcm_ioplug_t *ioplug, snd_pcm_state_t state)
1242 {
1243 ioplug->state = state;
1244 return 0;
1245 }
1246
1247 /**
1248 * \brief Get the available frames. This function can be used to calculate the
1249 * the available frames before calling #snd_pcm_avail_update()
1250 * \param ioplug the ioplug handle
1251 * \param hw_ptr hardware pointer in frames
1252 * \param appl_ptr application pointer in frames
1253 * \return available frames for the application
1254 */
snd_pcm_ioplug_avail(const snd_pcm_ioplug_t * const ioplug,const snd_pcm_uframes_t hw_ptr,const snd_pcm_uframes_t appl_ptr)1255 snd_pcm_uframes_t snd_pcm_ioplug_avail(const snd_pcm_ioplug_t * const ioplug,
1256 const snd_pcm_uframes_t hw_ptr,
1257 const snd_pcm_uframes_t appl_ptr)
1258 {
1259 return __snd_pcm_avail(ioplug->pcm, hw_ptr, appl_ptr);
1260 }
1261
1262 /**
1263 * \brief Get the available frames. This function can be used to calculate the
1264 * the available frames before calling #snd_pcm_avail_update()
1265 * \param ioplug the ioplug handle
1266 * \param hw_ptr hardware pointer in frames
1267 * \param appl_ptr application pointer in frames
1268 * \return available frames for the hardware
1269 */
snd_pcm_ioplug_hw_avail(const snd_pcm_ioplug_t * const ioplug,const snd_pcm_uframes_t hw_ptr,const snd_pcm_uframes_t appl_ptr)1270 snd_pcm_uframes_t snd_pcm_ioplug_hw_avail(const snd_pcm_ioplug_t * const ioplug,
1271 const snd_pcm_uframes_t hw_ptr,
1272 const snd_pcm_uframes_t appl_ptr)
1273 {
1274 /* available data/space which can be transferred by the user
1275 * application
1276 */
1277 const snd_pcm_uframes_t user_avail = snd_pcm_ioplug_avail(ioplug,
1278 hw_ptr,
1279 appl_ptr);
1280
1281 if (user_avail > ioplug->pcm->buffer_size) {
1282 /* there was an Xrun */
1283 return 0;
1284 }
1285 /* available data/space which can be transferred by the DMA */
1286 return ioplug->pcm->buffer_size - user_avail;
1287 }
1288