• Home
  • History
  • Annotate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/iserver/alsa-lib-1.0.26/src/pcm/

Lines Matching defs:*

2  * \file pcm/pcm_plugin.c
3 * \ingroup PCM
4 * \brief PCM Interface
5 * \author Jaroslav Kysela <perex@perex.cz>
6 * \author Abramo Bagnara <abramo@alsa-project.org>
7 * \date 2000-2001
10 * PCM - Common plugin code
11 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
14 * This library is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License as
16 * published by the Free Software Foundation; either version 2.1 of
17 * the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 \page pcm_plugins PCM (digital audio) plugins
34 PCM plugins extends functionality and features of PCM devices.
35 The plugins take care about various sample conversions, sample
36 copying among channels and so on.
38 \section pcm_plugins_slave Slave definition
40 The slave plugin can be specified directly with a string or the definition
41 can be entered inside a compound configuration node. Some restrictions can
42 be also specified (like static rate or count of channels).
44 \code
45 pcm_slave.NAME {
46 pcm STR # PCM name
47 # or
48 pcm { } # PCM definition
49 format STR # Format or "unchanged"
50 channels INT # Count of channels or "unchanged" string
51 rate INT # Rate in Hz or "unchanged" string
52 period_time INT # Period time in us or "unchanged" string
53 buffer_time INT # Buffer time in us or "unchanged" string
55 \endcode
57 Example:
59 \code
60 pcm_slave.slave_rate44100Hz {
61 pcm "hw:0,0"
62 rate 44100
65 pcm.rate44100Hz {
66 type plug
67 slave slave_rate44100Hz
69 \endcode
71 The equivalent configuration (in one compound):
73 \code
74 pcm.rate44100Hz {
75 type plug
76 slave {
77 pcm "hw:0,0"
78 rate 44100
81 \endcode
85 #include <sys/shm.h>
86 #include <limits.h>
87 #include "pcm_local.h"
88 #include "pcm_plugin.h"
90 #ifndef DOC_HIDDEN
92 static snd_pcm_sframes_t
93 snd_pcm_plugin_undo_read(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
94 const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED,
95 snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED,
96 snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED,
97 snd_pcm_uframes_t slave_undo_size ATTRIBUTE_UNUSED)
99 return -EIO;
102 static snd_pcm_sframes_t
103 snd_pcm_plugin_undo_write(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
104 const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED,
105 snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED,
106 snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED,
107 snd_pcm_uframes_t slave_undo_size ATTRIBUTE_UNUSED)
109 return -EIO;
112 snd_pcm_sframes_t
113 snd_pcm_plugin_undo_read_generic(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
114 const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED,
115 snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED,
116 snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED,
117 snd_pcm_uframes_t slave_undo_size)
119 return slave_undo_size;
122 snd_pcm_sframes_t
123 snd_pcm_plugin_undo_write_generic(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
124 const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED,
125 snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED,
126 snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED,
127 snd_pcm_uframes_t slave_undo_size)
129 return slave_undo_size;
132 void snd_pcm_plugin_init(snd_pcm_plugin_t *plugin)
134 memset(plugin, 0, sizeof(snd_pcm_plugin_t));
135 plugin->undo_read = snd_pcm_plugin_undo_read;
136 plugin->undo_write = snd_pcm_plugin_undo_write;
137 snd_atomic_write_init(&plugin->watom);
140 static int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
142 snd_pcm_plugin_t *plugin = pcm->private_data;
143 snd_pcm_sframes_t sd;
144 int err = snd_pcm_delay(plugin->gen.slave, &sd);
145 if (err < 0)
146 return err;
147 if (pcm->stream == SND_PCM_STREAM_CAPTURE &&
148 pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
149 pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
150 sd += snd_pcm_mmap_capture_avail(pcm);
153 *delayp = sd;
154 return 0;
157 static int snd_pcm_plugin_prepare(snd_pcm_t *pcm)
159 snd_pcm_plugin_t *plugin = pcm->private_data;
160 int err;
161 snd_atomic_write_begin(&plugin->watom);
162 err = snd_pcm_prepare(plugin->gen.slave);
163 if (err < 0) {
164 snd_atomic_write_end(&plugin->watom);
165 return err;
167 *pcm->hw.ptr = 0;
168 *pcm->appl.ptr = 0;
169 snd_atomic_write_end(&plugin->watom);
170 if (plugin->init) {
171 err = plugin->init(pcm);
172 if (err < 0)
173 return err;
175 return 0;
178 static int snd_pcm_plugin_reset(snd_pcm_t *pcm)
180 snd_pcm_plugin_t *plugin = pcm->private_data;
181 int err;
182 snd_atomic_write_begin(&plugin->watom);
183 err = snd_pcm_reset(plugin->gen.slave);
184 if (err < 0) {
185 snd_atomic_write_end(&plugin->watom);
186 return err;
188 *pcm->hw.ptr = 0;
189 *pcm->appl.ptr = 0;
190 snd_atomic_write_end(&plugin->watom);
191 if (plugin->init) {
192 err = plugin->init(pcm);
193 if (err < 0)
194 return err;
196 return 0;
199 static snd_pcm_sframes_t snd_pcm_plugin_rewindable(snd_pcm_t *pcm)
201 return snd_pcm_mmap_hw_avail(pcm);
204 static snd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
206 snd_pcm_plugin_t *plugin = pcm->private_data;
207 snd_pcm_sframes_t n = snd_pcm_mmap_hw_avail(pcm);
208 snd_pcm_sframes_t sframes;
210 if ((snd_pcm_uframes_t)n < frames)
211 frames = n;
212 if (frames == 0)
213 return 0;
215 sframes = frames;
216 snd_atomic_write_begin(&plugin->watom);
217 sframes = snd_pcm_rewind(plugin->gen.slave, sframes);
218 if (sframes < 0) {
219 snd_atomic_write_end(&plugin->watom);
220 return sframes;
222 snd_pcm_mmap_appl_backward(pcm, (snd_pcm_uframes_t) frames);
223 snd_atomic_write_end(&plugin->watom);
224 return (snd_pcm_sframes_t) frames;
227 static snd_pcm_sframes_t snd_pcm_plugin_forwardable(snd_pcm_t *pcm)
229 return snd_pcm_mmap_avail(pcm);
232 static snd_pcm_sframes_t snd_pcm_plugin_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
234 snd_pcm_plugin_t *plugin = pcm->private_data;
235 snd_pcm_sframes_t n = snd_pcm_mmap_avail(pcm);
236 snd_pcm_sframes_t sframes;
238 if ((snd_pcm_uframes_t)n < frames)
239 frames = n;
240 if (frames == 0)
241 return 0;
243 sframes = frames;
244 snd_atomic_write_begin(&plugin->watom);
245 sframes = INTERNAL(snd_pcm_forward)(plugin->gen.slave, sframes);
246 if (sframes < 0) {
247 snd_atomic_write_end(&plugin->watom);
248 return sframes;
250 snd_pcm_mmap_appl_forward(pcm, (snd_pcm_uframes_t) frames);
251 snd_atomic_write_end(&plugin->watom);
252 return (snd_pcm_sframes_t) frames;
255 static snd_pcm_sframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm,
256 const snd_pcm_channel_area_t *areas,
257 snd_pcm_uframes_t offset,
258 snd_pcm_uframes_t size)
260 snd_pcm_plugin_t *plugin = pcm->private_data;
261 snd_pcm_t *slave = plugin->gen.slave;
262 snd_pcm_uframes_t xfer = 0;
263 snd_pcm_sframes_t result;
264 int err;
266 while (size > 0) {
267 snd_pcm_uframes_t frames = size;
268 const snd_pcm_channel_area_t *slave_areas;
269 snd_pcm_uframes_t slave_offset;
270 snd_pcm_uframes_t slave_frames = ULONG_MAX;
272 err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
273 if (err < 0 || slave_frames == 0)
274 break;
275 frames = plugin->write(pcm, areas, offset, frames,
276 slave_areas, slave_offset, &slave_frames);
277 if (CHECK_SANITY(slave_frames > snd_pcm_mmap_playback_avail(slave))) {
278 SNDMSG("write overflow %ld > %ld", slave_frames,
279 snd_pcm_mmap_playback_avail(slave));
280 return -EPIPE;
282 snd_atomic_write_begin(&plugin->watom);
283 snd_pcm_mmap_appl_forward(pcm, frames);
284 result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
285 if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) {
286 snd_pcm_sframes_t res;
287 res = plugin->undo_write(pcm, slave_areas, slave_offset + result, slave_frames, slave_frames - result);
288 if (res < 0)
289 return xfer > 0 ? (snd_pcm_sframes_t)xfer : res;
290 frames -= res;
292 snd_atomic_write_end(&plugin->watom);
293 if (result <= 0)
294 return xfer > 0 ? (snd_pcm_sframes_t)xfer : result;
295 offset += frames;
296 xfer += frames;
297 size -= frames;
299 return (snd_pcm_sframes_t)xfer;
302 static snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm,
303 const snd_pcm_channel_area_t *areas,
304 snd_pcm_uframes_t offset,
305 snd_pcm_uframes_t size)
307 snd_pcm_plugin_t *plugin = pcm->private_data;
308 snd_pcm_t *slave = plugin->gen.slave;
309 snd_pcm_uframes_t xfer = 0;
310 snd_pcm_sframes_t result;
312 while (size > 0) {
313 snd_pcm_uframes_t frames = size;
314 const snd_pcm_channel_area_t *slave_areas;
315 snd_pcm_uframes_t slave_offset;
316 snd_pcm_uframes_t slave_frames = ULONG_MAX;
318 snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
319 if (slave_frames == 0)
320 break;
321 frames = (plugin->read)(pcm, areas, offset, frames,
322 slave_areas, slave_offset, &slave_frames);
323 if (CHECK_SANITY(slave_frames > snd_pcm_mmap_capture_avail(slave))) {
324 SNDMSG("read overflow %ld > %ld", slave_frames,
325 snd_pcm_mmap_playback_avail(slave));
326 return -EPIPE;
328 snd_atomic_write_begin(&plugin->watom);
329 snd_pcm_mmap_appl_forward(pcm, frames);
330 result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
331 if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) {
332 snd_pcm_sframes_t res;
334 res = plugin->undo_read(slave, areas, offset, frames, slave_frames - result);
335 if (res < 0)
336 return xfer > 0 ? (snd_pcm_sframes_t)xfer : res;
337 frames -= res;
339 snd_atomic_write_end(&plugin->watom);
340 if (result <= 0)
341 return xfer > 0 ? (snd_pcm_sframes_t)xfer : result;
342 offset += frames;
343 xfer += frames;
344 size -= frames;
346 return (snd_pcm_sframes_t)xfer;
350 static snd_pcm_sframes_t
351 snd_pcm_plugin_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
353 snd_pcm_channel_area_t areas[pcm->channels];
354 snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
355 return snd_pcm_write_areas(pcm, areas, 0, size,
356 snd_pcm_plugin_write_areas);
359 static snd_pcm_sframes_t
360 snd_pcm_plugin_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
362 snd_pcm_channel_area_t areas[pcm->channels];
363 snd_pcm_areas_from_bufs(pcm, areas, bufs);
364 return snd_pcm_write_areas(pcm, areas, 0, size,
365 snd_pcm_plugin_write_areas);
368 static snd_pcm_sframes_t
369 snd_pcm_plugin_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
371 snd_pcm_channel_area_t areas[pcm->channels];
372 snd_pcm_areas_from_buf(pcm, areas, buffer);
373 return snd_pcm_read_areas(pcm, areas, 0, size,
374 snd_pcm_plugin_read_areas);
377 static snd_pcm_sframes_t
378 snd_pcm_plugin_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
380 snd_pcm_channel_area_t areas[pcm->channels];
381 snd_pcm_areas_from_bufs(pcm, areas, bufs);
382 return snd_pcm_read_areas(pcm, areas, 0, size,
383 snd_pcm_plugin_read_areas);
386 static snd_pcm_sframes_t
387 snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm,
388 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
389 snd_pcm_uframes_t size)
391 snd_pcm_plugin_t *plugin = pcm->private_data;
392 snd_pcm_t *slave = plugin->gen.slave;
393 const snd_pcm_channel_area_t *areas;
394 snd_pcm_uframes_t appl_offset;
395 snd_pcm_sframes_t slave_size;
396 snd_pcm_sframes_t xfer;
398 if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
399 snd_atomic_write_begin(&plugin->watom);
400 snd_pcm_mmap_appl_forward(pcm, size);
401 snd_atomic_write_end(&plugin->watom);
402 return size;
404 slave_size = snd_pcm_avail_update(slave);
405 if (slave_size < 0)
406 return slave_size;
407 areas = snd_pcm_mmap_areas(pcm);
408 appl_offset = snd_pcm_mmap_offset(pcm);
409 xfer = 0;
410 while (size > 0 && slave_size > 0) {
411 snd_pcm_uframes_t frames = size;
412 snd_pcm_uframes_t cont = pcm->buffer_size - appl_offset;
413 const snd_pcm_channel_area_t *slave_areas;
414 snd_pcm_uframes_t slave_offset;
415 snd_pcm_uframes_t slave_frames = ULONG_MAX;
416 snd_pcm_sframes_t result;
417 int err;
419 err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
420 if (err < 0)
421 return xfer > 0 ? xfer : err;
422 if (frames > cont)
423 frames = cont;
424 frames = plugin->write(pcm, areas, appl_offset, frames,
425 slave_areas, slave_offset, &slave_frames);
426 snd_atomic_write_begin(&plugin->watom);
427 snd_pcm_mmap_appl_forward(pcm, frames);
428 result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
429 snd_atomic_write_end(&plugin->watom);
430 if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) {
431 snd_pcm_sframes_t res;
433 res = plugin->undo_write(pcm, slave_areas, slave_offset + result, slave_frames, slave_frames - result);
434 if (res < 0)
435 return xfer > 0 ? xfer : res;
436 frames -= res;
438 if (result <= 0)
439 return xfer > 0 ? xfer : result;
440 if (frames == cont)
441 appl_offset = 0;
442 else
443 appl_offset += result;
444 size -= frames;
445 slave_size -= frames;
446 xfer += frames;
448 if (CHECK_SANITY(size)) {
449 SNDMSG("short commit: %ld", size);
450 return -EPIPE;
452 return xfer;
455 static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
457 snd_pcm_plugin_t *plugin = pcm->private_data;
458 snd_pcm_t *slave = plugin->gen.slave;
459 snd_pcm_sframes_t slave_size;
461 slave_size = snd_pcm_avail_update(slave);
462 if (pcm->stream == SND_PCM_STREAM_CAPTURE &&
463 pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
464 pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED)
465 goto _capture;
466 *pcm->hw.ptr = *slave->hw.ptr;
467 return slave_size;
468 _capture:
470 const snd_pcm_channel_area_t *areas;
471 snd_pcm_uframes_t xfer, hw_offset, size;
473 xfer = snd_pcm_mmap_capture_avail(pcm);
474 size = pcm->buffer_size - xfer;
475 areas = snd_pcm_mmap_areas(pcm);
476 hw_offset = snd_pcm_mmap_hw_offset(pcm);
477 while (size > 0 && slave_size > 0) {
478 snd_pcm_uframes_t frames = size;
479 snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset;
480 const snd_pcm_channel_area_t *slave_areas;
481 snd_pcm_uframes_t slave_offset;
482 snd_pcm_uframes_t slave_frames = ULONG_MAX;
483 snd_pcm_sframes_t result;
484 int err;
486 err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
487 if (err < 0)
488 return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
489 if (frames > cont)
490 frames = cont;
491 frames = (plugin->read)(pcm, areas, hw_offset, frames,
492 slave_areas, slave_offset, &slave_frames);
493 snd_atomic_write_begin(&plugin->watom);
494 snd_pcm_mmap_hw_forward(pcm, frames);
495 result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
496 snd_atomic_write_end(&plugin->watom);
497 if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) {
498 snd_pcm_sframes_t res;
500 res = plugin->undo_read(slave, areas, hw_offset, frames, slave_frames - result);
501 if (res < 0)
502 return xfer > 0 ? (snd_pcm_sframes_t)xfer : res;
503 frames -= res;
505 if (result <= 0)
506 return xfer > 0 ? (snd_pcm_sframes_t)xfer : result;
507 if (frames == cont)
508 hw_offset = 0;
509 else
510 hw_offset += frames;
511 size -= frames;
512 slave_size -= slave_frames;
513 xfer += frames;
515 return (snd_pcm_sframes_t)xfer;
519 static int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
521 snd_pcm_plugin_t *plugin = pcm->private_data;
522 snd_pcm_sframes_t err;
523 snd_atomic_read_t ratom;
524 snd_atomic_read_init(&ratom, &plugin->watom);
525 _again:
526 snd_atomic_read_begin(&ratom);
527 /* sync with the latest hw and appl ptrs */
528 snd_pcm_plugin_avail_update(pcm);
530 err = snd_pcm_status(plugin->gen.slave, status);
531 if (err < 0) {
532 snd_atomic_read_ok(&ratom);
533 return err;
535 status->appl_ptr = *pcm->appl.ptr;
536 status->hw_ptr = *pcm->hw.ptr;
537 if (!snd_atomic_read_ok(&ratom)) {
538 snd_atomic_read_wait(&ratom);
539 goto _again;
541 return 0;
544 const snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = {
545 .status = snd_pcm_plugin_status,
546 .state = snd_pcm_generic_state,
547 .hwsync = snd_pcm_generic_hwsync,
548 .delay = snd_pcm_plugin_delay,
549 .prepare = snd_pcm_plugin_prepare,
550 .reset = snd_pcm_plugin_reset,
551 .start = snd_pcm_generic_start,
552 .drop = snd_pcm_generic_drop,
553 .drain = snd_pcm_generic_drain,
554 .pause = snd_pcm_generic_pause,
555 .rewindable = snd_pcm_plugin_rewindable,
556 .rewind = snd_pcm_plugin_rewind,
557 .forwardable = snd_pcm_plugin_forwardable,
558 .forward = snd_pcm_plugin_forward,
559 .resume = snd_pcm_generic_resume,
560 .link = snd_pcm_generic_link,
561 .link_slaves = snd_pcm_generic_link_slaves,
562 .unlink = snd_pcm_generic_unlink,
563 .writei = snd_pcm_plugin_writei,
564 .writen = snd_pcm_plugin_writen,
565 .readi = snd_pcm_plugin_readi,
566 .readn = snd_pcm_plugin_readn,
567 .avail_update = snd_pcm_plugin_avail_update,
568 .mmap_commit = snd_pcm_plugin_mmap_commit,
569 .htimestamp = snd_pcm_generic_htimestamp,
570 .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
571 .poll_descriptors = snd_pcm_generic_poll_descriptors,
572 .poll_revents = snd_pcm_generic_poll_revents,
575 #endif