2 * \file pcm/pcm_dsnoop.c
4 * \brief PCM Capture Stream Snooping (dsnoop) Plugin Interface
5 * \author Jaroslav Kysela <perex@perex.cz>
9 * PCM - Capture Stream Snooping
10 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
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
38 #include <sys/ioctl.h>
43 #include <sys/socket.h>
46 #include "pcm_direct.h"
49 /* entry for static linking */
50 const char *_snd_module_pcm_dsnoop = "";
57 static int snoop_timestamp(snd_pcm_t *pcm)
59 snd_pcm_direct_t *dsnoop = pcm->private_data;
60 snd_pcm_uframes_t ptr1 = -2LL /* invalid value */, ptr2;
62 /* loop is required to sync hw.ptr with timestamp */
64 ptr2 = *dsnoop->spcm->hw.ptr;
68 dsnoop->update_tstamp = snd_pcm_hw_fast_tstamp(dsnoop->spcm);
70 dsnoop->slave_hw_ptr = ptr1;
74 static void snoop_areas(snd_pcm_direct_t *dsnoop,
75 const snd_pcm_channel_area_t *src_areas,
76 const snd_pcm_channel_area_t *dst_areas,
77 snd_pcm_uframes_t src_ofs,
78 snd_pcm_uframes_t dst_ofs,
79 snd_pcm_uframes_t size)
81 unsigned int chn, schn, channels;
82 snd_pcm_format_t format;
84 channels = dsnoop->channels;
85 format = dsnoop->shmptr->s.format;
86 if (dsnoop->interleaved) {
87 unsigned int fbytes = snd_pcm_format_physical_width(format) / 8;
88 memcpy(((char *)dst_areas[0].addr) + (dst_ofs * channels * fbytes),
89 ((char *)src_areas[0].addr) + (src_ofs * channels * fbytes),
90 size * channels * fbytes);
92 for (chn = 0; chn < channels; chn++) {
93 schn = dsnoop->bindings ? dsnoop->bindings[chn] : chn;
94 snd_pcm_area_copy(&dst_areas[chn], dst_ofs, &src_areas[schn], src_ofs, size, format);
100 * synchronize shm ring buffer with hardware
102 static void snd_pcm_dsnoop_sync_area(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr, snd_pcm_uframes_t size)
104 snd_pcm_direct_t *dsnoop = pcm->private_data;
105 snd_pcm_uframes_t hw_ptr = dsnoop->hw_ptr;
106 snd_pcm_uframes_t transfer;
107 const snd_pcm_channel_area_t *src_areas, *dst_areas;
109 /* add sample areas here */
110 dst_areas = snd_pcm_mmap_areas(pcm);
111 src_areas = snd_pcm_mmap_areas(dsnoop->spcm);
112 hw_ptr %= pcm->buffer_size;
113 slave_hw_ptr %= dsnoop->slave_buffer_size;
115 transfer = hw_ptr + size > pcm->buffer_size ? pcm->buffer_size - hw_ptr : size;
116 transfer = slave_hw_ptr + transfer > dsnoop->slave_buffer_size ?
117 dsnoop->slave_buffer_size - slave_hw_ptr : transfer;
119 snoop_areas(dsnoop, src_areas, dst_areas, slave_hw_ptr, hw_ptr, transfer);
120 slave_hw_ptr += transfer;
121 slave_hw_ptr %= dsnoop->slave_buffer_size;
123 hw_ptr %= pcm->buffer_size;
128 * synchronize hardware pointer (hw_ptr) with ours
130 static int snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm)
132 snd_pcm_direct_t *dsnoop = pcm->private_data;
133 snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail;
134 snd_pcm_sframes_t diff;
136 switch (snd_pcm_state(dsnoop->spcm)) {
137 case SND_PCM_STATE_DISCONNECTED:
138 dsnoop->state = SNDRV_PCM_STATE_DISCONNECTED;
144 snd_pcm_hwsync(dsnoop->spcm);
145 old_slave_hw_ptr = dsnoop->slave_hw_ptr;
146 snoop_timestamp(pcm);
147 slave_hw_ptr = dsnoop->slave_hw_ptr;
148 diff = slave_hw_ptr - old_slave_hw_ptr;
149 if (diff == 0) /* fast path */
152 slave_hw_ptr += dsnoop->slave_boundary;
153 diff = slave_hw_ptr - old_slave_hw_ptr;
155 snd_pcm_dsnoop_sync_area(pcm, old_slave_hw_ptr, diff);
156 dsnoop->hw_ptr += diff;
157 dsnoop->hw_ptr %= pcm->boundary;
158 // printf("sync ptr diff = %li\n", diff);
159 if (pcm->stop_threshold >= pcm->boundary) /* don't care */
161 if ((avail = snd_pcm_mmap_capture_hw_avail(pcm)) >= pcm->stop_threshold) {
162 gettimestamp(&dsnoop->trigger_tstamp, pcm->monotonic);
163 dsnoop->state = SND_PCM_STATE_XRUN;
164 dsnoop->avail_max = avail;
167 if (avail > dsnoop->avail_max)
168 dsnoop->avail_max = avail;
173 * plugin implementation
176 static int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
178 snd_pcm_direct_t *dsnoop = pcm->private_data;
179 snd_pcm_state_t state;
181 switch(dsnoop->state) {
182 case SNDRV_PCM_STATE_DRAINING:
183 case SNDRV_PCM_STATE_RUNNING:
184 snd_pcm_dsnoop_sync_ptr(pcm);
189 memset(status, 0, sizeof(*status));
190 state = snd_pcm_state(dsnoop->spcm);
191 status->state = state == SND_PCM_STATE_RUNNING ? dsnoop->state : state;
192 status->trigger_tstamp = dsnoop->trigger_tstamp;
193 status->tstamp = dsnoop->update_tstamp;
194 status->avail = snd_pcm_mmap_capture_avail(pcm);
195 status->avail_max = status->avail > dsnoop->avail_max ? status->avail : dsnoop->avail_max;
196 dsnoop->avail_max = 0;
200 static snd_pcm_state_t snd_pcm_dsnoop_state(snd_pcm_t *pcm)
202 snd_pcm_direct_t *dsnoop = pcm->private_data;
203 switch (snd_pcm_state(dsnoop->spcm)) {
204 case SND_PCM_STATE_SUSPENDED:
205 return SND_PCM_STATE_SUSPENDED;
206 case SND_PCM_STATE_DISCONNECTED:
207 dsnoop->state = SNDRV_PCM_STATE_DISCONNECTED;
212 return dsnoop->state;
215 static int snd_pcm_dsnoop_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
217 snd_pcm_direct_t *dsnoop = pcm->private_data;
220 switch(dsnoop->state) {
221 case SNDRV_PCM_STATE_DRAINING:
222 case SNDRV_PCM_STATE_RUNNING:
223 err = snd_pcm_dsnoop_sync_ptr(pcm);
227 case SNDRV_PCM_STATE_PREPARED:
228 case SNDRV_PCM_STATE_SUSPENDED:
229 *delayp = snd_pcm_mmap_capture_hw_avail(pcm);
231 case SNDRV_PCM_STATE_XRUN:
233 case SNDRV_PCM_STATE_DISCONNECTED:
240 static int snd_pcm_dsnoop_hwsync(snd_pcm_t *pcm)
242 snd_pcm_direct_t *dsnoop = pcm->private_data;
244 switch(dsnoop->state) {
245 case SNDRV_PCM_STATE_DRAINING:
246 case SNDRV_PCM_STATE_RUNNING:
247 return snd_pcm_dsnoop_sync_ptr(pcm);
248 case SNDRV_PCM_STATE_PREPARED:
249 case SNDRV_PCM_STATE_SUSPENDED:
251 case SNDRV_PCM_STATE_XRUN:
253 case SNDRV_PCM_STATE_DISCONNECTED:
260 static int snd_pcm_dsnoop_prepare(snd_pcm_t *pcm)
262 snd_pcm_direct_t *dsnoop = pcm->private_data;
264 snd_pcm_direct_check_interleave(dsnoop, pcm);
265 dsnoop->state = SND_PCM_STATE_PREPARED;
266 dsnoop->appl_ptr = 0;
268 return snd_pcm_direct_set_timer_params(dsnoop);
271 static int snd_pcm_dsnoop_reset(snd_pcm_t *pcm)
273 snd_pcm_direct_t *dsnoop = pcm->private_data;
274 dsnoop->hw_ptr %= pcm->period_size;
275 dsnoop->appl_ptr = dsnoop->hw_ptr;
276 dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr;
280 static int snd_pcm_dsnoop_start(snd_pcm_t *pcm)
282 snd_pcm_direct_t *dsnoop = pcm->private_data;
285 if (dsnoop->state != SND_PCM_STATE_PREPARED)
287 snd_pcm_hwsync(dsnoop->spcm);
288 snoop_timestamp(pcm);
289 dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr;
290 err = snd_timer_start(dsnoop->timer);
293 dsnoop->state = SND_PCM_STATE_RUNNING;
294 dsnoop->trigger_tstamp = dsnoop->update_tstamp;
298 static int snd_pcm_dsnoop_drop(snd_pcm_t *pcm)
300 snd_pcm_direct_t *dsnoop = pcm->private_data;
301 if (dsnoop->state == SND_PCM_STATE_OPEN)
303 dsnoop->state = SND_PCM_STATE_SETUP;
304 snd_timer_stop(dsnoop->timer);
308 static int snd_pcm_dsnoop_drain(snd_pcm_t *pcm)
310 snd_pcm_direct_t *dsnoop = pcm->private_data;
311 snd_pcm_uframes_t stop_threshold;
314 if (dsnoop->state == SND_PCM_STATE_OPEN)
316 stop_threshold = pcm->stop_threshold;
317 if (pcm->stop_threshold > pcm->buffer_size)
318 pcm->stop_threshold = pcm->buffer_size;
319 while (dsnoop->state == SND_PCM_STATE_RUNNING) {
320 err = snd_pcm_dsnoop_sync_ptr(pcm);
323 if (pcm->mode & SND_PCM_NONBLOCK)
325 snd_pcm_wait(pcm, -1);
327 pcm->stop_threshold = stop_threshold;
328 return snd_pcm_dsnoop_drop(pcm);
331 static int snd_pcm_dsnoop_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
336 static snd_pcm_sframes_t snd_pcm_dsnoop_rewindable(snd_pcm_t *pcm)
338 return snd_pcm_mmap_capture_avail(pcm);
341 static snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
343 snd_pcm_sframes_t avail;
345 avail = snd_pcm_mmap_capture_avail(pcm);
348 if (frames > (snd_pcm_uframes_t)avail)
350 snd_pcm_mmap_appl_backward(pcm, frames);
354 static snd_pcm_sframes_t snd_pcm_dsnoop_forwardable(snd_pcm_t *pcm)
356 return snd_pcm_mmap_capture_hw_avail(pcm);
359 static snd_pcm_sframes_t snd_pcm_dsnoop_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
361 snd_pcm_sframes_t avail;
363 avail = snd_pcm_mmap_capture_hw_avail(pcm);
366 if (frames > (snd_pcm_uframes_t)avail)
368 snd_pcm_mmap_appl_forward(pcm, frames);
372 static snd_pcm_sframes_t snd_pcm_dsnoop_writei(snd_pcm_t *pcm ATTRIBUTE_UNUSED, const void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
377 static snd_pcm_sframes_t snd_pcm_dsnoop_writen(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
382 static int snd_pcm_dsnoop_close(snd_pcm_t *pcm)
384 snd_pcm_direct_t *dsnoop = pcm->private_data;
387 snd_timer_close(dsnoop->timer);
388 snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
389 snd_pcm_close(dsnoop->spcm);
391 snd_pcm_direct_server_discard(dsnoop);
393 snd_pcm_direct_client_discard(dsnoop);
394 if (snd_pcm_direct_shm_discard(dsnoop))
395 snd_pcm_direct_semaphore_discard(dsnoop);
397 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
398 free(dsnoop->bindings);
399 pcm->private_data = NULL;
404 static snd_pcm_sframes_t snd_pcm_dsnoop_mmap_commit(snd_pcm_t *pcm,
405 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
406 snd_pcm_uframes_t size)
408 snd_pcm_direct_t *dsnoop = pcm->private_data;
411 switch (snd_pcm_state(dsnoop->spcm)) {
412 case SND_PCM_STATE_XRUN:
414 case SND_PCM_STATE_SUSPENDED:
419 if (dsnoop->state == SND_PCM_STATE_RUNNING) {
420 err = snd_pcm_dsnoop_sync_ptr(pcm);
424 snd_pcm_mmap_appl_forward(pcm, size);
425 /* clear timer queue to avoid a bogus return from poll */
426 if (snd_pcm_mmap_capture_avail(pcm) < pcm->avail_min)
427 snd_pcm_direct_clear_timer_queue(dsnoop);
431 static snd_pcm_sframes_t snd_pcm_dsnoop_avail_update(snd_pcm_t *pcm)
433 snd_pcm_direct_t *dsnoop = pcm->private_data;
436 if (dsnoop->state == SND_PCM_STATE_RUNNING) {
437 err = snd_pcm_dsnoop_sync_ptr(pcm);
441 return snd_pcm_mmap_capture_avail(pcm);
444 static int snd_pcm_dsnoop_htimestamp(snd_pcm_t *pcm,
445 snd_pcm_uframes_t *avail,
446 snd_htimestamp_t *tstamp)
448 snd_pcm_direct_t *dsnoop = pcm->private_data;
449 snd_pcm_uframes_t avail1;
453 if (dsnoop->state == SND_PCM_STATE_RUNNING ||
454 dsnoop->state == SND_PCM_STATE_DRAINING)
455 snd_pcm_dsnoop_sync_ptr(pcm);
456 avail1 = snd_pcm_mmap_capture_avail(pcm);
457 if (ok && *avail == avail1)
460 *tstamp = snd_pcm_hw_fast_tstamp(dsnoop->spcm);
465 static void snd_pcm_dsnoop_dump(snd_pcm_t *pcm, snd_output_t *out)
467 snd_pcm_direct_t *dsnoop = pcm->private_data;
469 snd_output_printf(out, "Direct Snoop PCM\n");
471 snd_output_printf(out, "Its setup is:\n");
472 snd_pcm_dump_setup(pcm, out);
475 snd_pcm_dump(dsnoop->spcm, out);
478 static const snd_pcm_ops_t snd_pcm_dsnoop_ops = {
479 .close = snd_pcm_dsnoop_close,
480 .info = snd_pcm_direct_info,
481 .hw_refine = snd_pcm_direct_hw_refine,
482 .hw_params = snd_pcm_direct_hw_params,
483 .hw_free = snd_pcm_direct_hw_free,
484 .sw_params = snd_pcm_direct_sw_params,
485 .channel_info = snd_pcm_direct_channel_info,
486 .dump = snd_pcm_dsnoop_dump,
487 .nonblock = snd_pcm_direct_nonblock,
488 .async = snd_pcm_direct_async,
489 .mmap = snd_pcm_direct_mmap,
490 .munmap = snd_pcm_direct_munmap,
491 .query_chmaps = snd_pcm_direct_query_chmaps,
492 .get_chmap = snd_pcm_direct_get_chmap,
493 .set_chmap = snd_pcm_direct_set_chmap,
496 static const snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = {
497 .status = snd_pcm_dsnoop_status,
498 .state = snd_pcm_dsnoop_state,
499 .hwsync = snd_pcm_dsnoop_hwsync,
500 .delay = snd_pcm_dsnoop_delay,
501 .prepare = snd_pcm_dsnoop_prepare,
502 .reset = snd_pcm_dsnoop_reset,
503 .start = snd_pcm_dsnoop_start,
504 .drop = snd_pcm_dsnoop_drop,
505 .drain = snd_pcm_dsnoop_drain,
506 .pause = snd_pcm_dsnoop_pause,
507 .rewindable = snd_pcm_dsnoop_rewindable,
508 .rewind = snd_pcm_dsnoop_rewind,
509 .forwardable = snd_pcm_dsnoop_forwardable,
510 .forward = snd_pcm_dsnoop_forward,
511 .resume = snd_pcm_direct_resume,
515 .writei = snd_pcm_dsnoop_writei,
516 .writen = snd_pcm_dsnoop_writen,
517 .readi = snd_pcm_mmap_readi,
518 .readn = snd_pcm_mmap_readn,
519 .avail_update = snd_pcm_dsnoop_avail_update,
520 .mmap_commit = snd_pcm_dsnoop_mmap_commit,
521 .htimestamp = snd_pcm_dsnoop_htimestamp,
522 .poll_descriptors = NULL,
523 .poll_descriptors_count = NULL,
524 .poll_revents = snd_pcm_direct_poll_revents,
528 * \brief Creates a new dsnoop PCM
529 * \param pcmp Returns created PCM handle
530 * \param name Name of PCM
531 * \param opts Direct PCM configurations
532 * \param params Parameters for slave
533 * \param root Configuration root
534 * \param sconf Slave configuration
535 * \param stream PCM Direction (stream)
536 * \param mode PCM Mode
537 * \retval zero on success otherwise a negative error code
538 * \warning Using of this function might be dangerous in the sense
539 * of compatibility reasons. The prototype might be freely
542 int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
543 struct snd_pcm_direct_open_conf *opts,
544 struct slave_params *params,
545 snd_config_t *root, snd_config_t *sconf,
546 snd_pcm_stream_t stream, int mode)
548 snd_pcm_t *pcm = NULL, *spcm = NULL;
549 snd_pcm_direct_t *dsnoop = NULL;
550 int ret, first_instance, fail_sem_loop = 10;
554 if (stream != SND_PCM_STREAM_CAPTURE) {
555 SNDERR("The dsnoop plugin supports only capture stream");
559 dsnoop = calloc(1, sizeof(snd_pcm_direct_t));
565 ret = snd_pcm_direct_parse_bindings(dsnoop, params, opts->bindings);
569 dsnoop->ipc_key = opts->ipc_key;
570 dsnoop->ipc_perm = opts->ipc_perm;
571 dsnoop->ipc_gid = opts->ipc_gid;
575 ret = snd_pcm_new(&pcm, dsnoop->type = SND_PCM_TYPE_DSNOOP, name, stream, mode);
580 ret = snd_pcm_direct_semaphore_create_or_connect(dsnoop);
582 SNDERR("unable to create IPC semaphore");
586 ret = snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
588 snd_pcm_direct_semaphore_discard(dsnoop);
589 if (--fail_sem_loop <= 0)
596 first_instance = ret = snd_pcm_direct_shm_create_or_connect(dsnoop);
598 SNDERR("unable to create IPC shm instance");
602 pcm->ops = &snd_pcm_dsnoop_ops;
603 pcm->fast_ops = &snd_pcm_dsnoop_fast_ops;
604 pcm->private_data = dsnoop;
605 dsnoop->state = SND_PCM_STATE_OPEN;
606 dsnoop->slowptr = opts->slowptr;
607 dsnoop->max_periods = opts->max_periods;
608 dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr;
610 if (first_instance) {
611 /* recursion is already checked in
612 snd_pcm_direct_get_slave_ipc_offset() */
613 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
614 mode | SND_PCM_NONBLOCK, NULL);
616 SNDERR("unable to open slave");
620 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
621 SNDERR("dsnoop plugin can be only connected to hw plugin");
625 ret = snd_pcm_direct_initialize_slave(dsnoop, spcm, params);
627 SNDERR("unable to initialize slave");
633 if (dsnoop->shmptr->use_server) {
634 ret = snd_pcm_direct_server_create(dsnoop);
636 SNDERR("unable to create server");
641 dsnoop->shmptr->type = spcm->type;
643 if (dsnoop->shmptr->use_server) {
644 /* up semaphore to avoid deadlock */
645 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
646 ret = snd_pcm_direct_client_connect(dsnoop);
648 SNDERR("unable to connect client");
652 snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
654 ret = snd_pcm_direct_open_secondary_client(&spcm, dsnoop, "dsnoop_client");
659 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
660 mode | SND_PCM_NONBLOCK |
664 SNDERR("unable to open slave");
667 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
668 SNDERR("dsnoop plugin can be only connected to hw plugin");
673 ret = snd_pcm_direct_initialize_secondary_slave(dsnoop, spcm, params);
675 SNDERR("unable to initialize slave");
683 ret = snd_pcm_direct_initialize_poll_fd(dsnoop);
685 SNDERR("unable to initialize poll_fd");
689 pcm->poll_fd = dsnoop->poll_fd;
690 pcm->poll_events = POLLIN; /* it's different than other plugins */
693 snd_pcm_set_hw_ptr(pcm, &dsnoop->hw_ptr, -1, 0);
694 snd_pcm_set_appl_ptr(pcm, &dsnoop->appl_ptr, -1, 0);
696 if (dsnoop->channels == UINT_MAX)
697 dsnoop->channels = dsnoop->shmptr->s.channels;
699 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
706 snd_timer_close(dsnoop->timer);
708 snd_pcm_direct_server_discard(dsnoop);
710 snd_pcm_direct_client_discard(dsnoop);
713 if (dsnoop->shmid >= 0)
714 snd_pcm_direct_shm_discard(dsnoop);
715 if (snd_pcm_direct_semaphore_discard(dsnoop) < 0)
716 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
719 free(dsnoop->bindings);
727 /*! \page pcm_plugins
729 \section pcm_plugins_dsnoop Plugin: dsnoop
731 This plugin splits one capture stream to more.
732 It works the reverse way of \ref pcm_plugins_dmix "dmix plugin",
733 reading the shared capture buffer from many clients concurrently.
734 The meaning of parameters below are almost identical with
739 type dsnoop # Direct snoop
740 ipc_key INT # unique IPC key
741 ipc_key_add_uid BOOL # add current uid to unique IPC key
742 ipc_perm INT # IPC permissions (octal, default 0600)
745 slave { # Slave definition
746 pcm STR # slave PCM name
748 pcm { } # slave PCM definition
749 format STR # format definition
750 rate INT # rate definition
752 period_time INT # in usec
754 period_size INT # in bytes
755 buffer_time INT # in usec
757 buffer_size INT # in bytes
758 periods INT # when buffer_size or buffer_time is not specified
760 bindings { # note: this is client independent!!!
761 N INT # maps slave channel to client channel N
763 slowptr BOOL # slow but more precise pointer updates
767 \subsection pcm_plugins_dsnoop_funcref Function reference
770 <LI>snd_pcm_dsnoop_open()
771 <LI>_snd_pcm_dsnoop_open()
777 * \brief Creates a new dsnoop PCM
778 * \param pcmp Returns created PCM handle
779 * \param name Name of PCM
780 * \param root Root configuration node
781 * \param conf Configuration node with dsnoop PCM description
782 * \param stream PCM Stream
783 * \param mode PCM Mode
784 * \warning Using of this function might be dangerous in the sense
785 * of compatibility reasons. The prototype might be freely
788 int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
789 snd_config_t *root, snd_config_t *conf,
790 snd_pcm_stream_t stream, int mode)
793 struct slave_params params;
794 struct snd_pcm_direct_open_conf dopen;
798 err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
802 /* the default settings, it might be invalid for some hardware */
803 params.format = SND_PCM_FORMAT_S16;
806 params.period_time = -1;
807 params.buffer_time = -1;
810 err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
811 SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format,
812 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
813 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
814 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
815 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
816 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
817 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
818 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
822 /* set a reasonable default */
823 if (psize == -1 && params.period_time == -1)
824 params.period_time = 125000; /* 0.125 seconds */
826 if (params.format == -2)
827 params.format = SND_PCM_FORMAT_UNKNOWN;
829 params.period_size = psize;
830 params.buffer_size = bsize;
832 err = snd_pcm_dsnoop_open(pcmp, name, &dopen, ¶ms,
833 root, sconf, stream, mode);
834 snd_config_delete(sconf);
838 SND_DLSYM_BUILD_VERSION(_snd_pcm_dsnoop_open, SND_PCM_DLSYM_VERSION);