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);
226 case SNDRV_PCM_STATE_PREPARED:
227 case SNDRV_PCM_STATE_SUSPENDED:
228 *delayp = snd_pcm_mmap_capture_hw_avail(pcm);
230 case SNDRV_PCM_STATE_XRUN:
232 case SNDRV_PCM_STATE_DISCONNECTED:
239 static int snd_pcm_dsnoop_hwsync(snd_pcm_t *pcm)
241 snd_pcm_direct_t *dsnoop = pcm->private_data;
243 switch(dsnoop->state) {
244 case SNDRV_PCM_STATE_DRAINING:
245 case SNDRV_PCM_STATE_RUNNING:
246 return snd_pcm_dsnoop_sync_ptr(pcm);
247 case SNDRV_PCM_STATE_PREPARED:
248 case SNDRV_PCM_STATE_SUSPENDED:
250 case SNDRV_PCM_STATE_XRUN:
252 case SNDRV_PCM_STATE_DISCONNECTED:
259 static int snd_pcm_dsnoop_prepare(snd_pcm_t *pcm)
261 snd_pcm_direct_t *dsnoop = pcm->private_data;
263 snd_pcm_direct_check_interleave(dsnoop, pcm);
264 dsnoop->state = SND_PCM_STATE_PREPARED;
265 dsnoop->appl_ptr = 0;
267 return snd_pcm_direct_set_timer_params(dsnoop);
270 static int snd_pcm_dsnoop_reset(snd_pcm_t *pcm)
272 snd_pcm_direct_t *dsnoop = pcm->private_data;
273 dsnoop->hw_ptr %= pcm->period_size;
274 dsnoop->appl_ptr = dsnoop->hw_ptr;
275 dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr;
279 static int snd_pcm_dsnoop_start(snd_pcm_t *pcm)
281 snd_pcm_direct_t *dsnoop = pcm->private_data;
284 if (dsnoop->state != SND_PCM_STATE_PREPARED)
286 snd_pcm_hwsync(dsnoop->spcm);
287 snoop_timestamp(pcm);
288 dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr;
289 err = snd_timer_start(dsnoop->timer);
292 dsnoop->state = SND_PCM_STATE_RUNNING;
293 dsnoop->trigger_tstamp = dsnoop->update_tstamp;
297 static int snd_pcm_dsnoop_drop(snd_pcm_t *pcm)
299 snd_pcm_direct_t *dsnoop = pcm->private_data;
300 if (dsnoop->state == SND_PCM_STATE_OPEN)
302 dsnoop->state = SND_PCM_STATE_SETUP;
303 snd_timer_stop(dsnoop->timer);
307 static int snd_pcm_dsnoop_drain(snd_pcm_t *pcm)
309 snd_pcm_direct_t *dsnoop = pcm->private_data;
310 snd_pcm_uframes_t stop_threshold;
313 if (dsnoop->state == SND_PCM_STATE_OPEN)
315 stop_threshold = pcm->stop_threshold;
316 if (pcm->stop_threshold > pcm->buffer_size)
317 pcm->stop_threshold = pcm->buffer_size;
318 while (dsnoop->state == SND_PCM_STATE_RUNNING) {
319 err = snd_pcm_dsnoop_sync_ptr(pcm);
322 if (pcm->mode & SND_PCM_NONBLOCK)
324 snd_pcm_wait(pcm, -1);
326 pcm->stop_threshold = stop_threshold;
327 return snd_pcm_dsnoop_drop(pcm);
330 static int snd_pcm_dsnoop_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
335 static snd_pcm_sframes_t snd_pcm_dsnoop_rewindable(snd_pcm_t *pcm)
337 return snd_pcm_mmap_capture_avail(pcm);
340 static snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
342 snd_pcm_sframes_t avail;
344 avail = snd_pcm_mmap_capture_avail(pcm);
347 if (frames > (snd_pcm_uframes_t)avail)
349 snd_pcm_mmap_appl_backward(pcm, frames);
353 static snd_pcm_sframes_t snd_pcm_dsnoop_forwardable(snd_pcm_t *pcm)
355 return snd_pcm_mmap_capture_hw_avail(pcm);
358 static snd_pcm_sframes_t snd_pcm_dsnoop_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
360 snd_pcm_sframes_t avail;
362 avail = snd_pcm_mmap_capture_hw_avail(pcm);
365 if (frames > (snd_pcm_uframes_t)avail)
367 snd_pcm_mmap_appl_forward(pcm, frames);
371 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)
376 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)
381 static int snd_pcm_dsnoop_close(snd_pcm_t *pcm)
383 snd_pcm_direct_t *dsnoop = pcm->private_data;
386 snd_timer_close(dsnoop->timer);
387 snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
388 snd_pcm_close(dsnoop->spcm);
390 snd_pcm_direct_server_discard(dsnoop);
392 snd_pcm_direct_client_discard(dsnoop);
393 if (snd_pcm_direct_shm_discard(dsnoop))
394 snd_pcm_direct_semaphore_discard(dsnoop);
396 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
397 free(dsnoop->bindings);
398 pcm->private_data = NULL;
403 static snd_pcm_sframes_t snd_pcm_dsnoop_mmap_commit(snd_pcm_t *pcm,
404 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
405 snd_pcm_uframes_t size)
407 snd_pcm_direct_t *dsnoop = pcm->private_data;
410 switch (snd_pcm_state(dsnoop->spcm)) {
411 case SND_PCM_STATE_XRUN:
413 case SND_PCM_STATE_SUSPENDED:
418 if (dsnoop->state == SND_PCM_STATE_RUNNING) {
419 err = snd_pcm_dsnoop_sync_ptr(pcm);
423 snd_pcm_mmap_appl_forward(pcm, size);
424 /* clear timer queue to avoid a bogus return from poll */
425 if (snd_pcm_mmap_capture_avail(pcm) < pcm->avail_min)
426 snd_pcm_direct_clear_timer_queue(dsnoop);
430 static snd_pcm_sframes_t snd_pcm_dsnoop_avail_update(snd_pcm_t *pcm)
432 snd_pcm_direct_t *dsnoop = pcm->private_data;
435 if (dsnoop->state == SND_PCM_STATE_RUNNING) {
436 err = snd_pcm_dsnoop_sync_ptr(pcm);
440 return snd_pcm_mmap_capture_avail(pcm);
443 static int snd_pcm_dsnoop_htimestamp(snd_pcm_t *pcm,
444 snd_pcm_uframes_t *avail,
445 snd_htimestamp_t *tstamp)
447 snd_pcm_direct_t *dsnoop = pcm->private_data;
448 snd_pcm_uframes_t avail1;
452 if (dsnoop->state == SND_PCM_STATE_RUNNING ||
453 dsnoop->state == SND_PCM_STATE_DRAINING)
454 snd_pcm_dsnoop_sync_ptr(pcm);
455 avail1 = snd_pcm_mmap_capture_avail(pcm);
456 if (ok && *avail == avail1)
459 *tstamp = snd_pcm_hw_fast_tstamp(dsnoop->spcm);
464 static void snd_pcm_dsnoop_dump(snd_pcm_t *pcm, snd_output_t *out)
466 snd_pcm_direct_t *dsnoop = pcm->private_data;
468 snd_output_printf(out, "Direct Snoop PCM\n");
470 snd_output_printf(out, "Its setup is:\n");
471 snd_pcm_dump_setup(pcm, out);
474 snd_pcm_dump(dsnoop->spcm, out);
477 static const snd_pcm_ops_t snd_pcm_dsnoop_ops = {
478 .close = snd_pcm_dsnoop_close,
479 .info = snd_pcm_direct_info,
480 .hw_refine = snd_pcm_direct_hw_refine,
481 .hw_params = snd_pcm_direct_hw_params,
482 .hw_free = snd_pcm_direct_hw_free,
483 .sw_params = snd_pcm_direct_sw_params,
484 .channel_info = snd_pcm_direct_channel_info,
485 .dump = snd_pcm_dsnoop_dump,
486 .nonblock = snd_pcm_direct_nonblock,
487 .async = snd_pcm_direct_async,
488 .mmap = snd_pcm_direct_mmap,
489 .munmap = snd_pcm_direct_munmap,
492 static const snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = {
493 .status = snd_pcm_dsnoop_status,
494 .state = snd_pcm_dsnoop_state,
495 .hwsync = snd_pcm_dsnoop_hwsync,
496 .delay = snd_pcm_dsnoop_delay,
497 .prepare = snd_pcm_dsnoop_prepare,
498 .reset = snd_pcm_dsnoop_reset,
499 .start = snd_pcm_dsnoop_start,
500 .drop = snd_pcm_dsnoop_drop,
501 .drain = snd_pcm_dsnoop_drain,
502 .pause = snd_pcm_dsnoop_pause,
503 .rewindable = snd_pcm_dsnoop_rewindable,
504 .rewind = snd_pcm_dsnoop_rewind,
505 .forwardable = snd_pcm_dsnoop_forwardable,
506 .forward = snd_pcm_dsnoop_forward,
507 .resume = snd_pcm_direct_resume,
511 .writei = snd_pcm_dsnoop_writei,
512 .writen = snd_pcm_dsnoop_writen,
513 .readi = snd_pcm_mmap_readi,
514 .readn = snd_pcm_mmap_readn,
515 .avail_update = snd_pcm_dsnoop_avail_update,
516 .mmap_commit = snd_pcm_dsnoop_mmap_commit,
517 .htimestamp = snd_pcm_dsnoop_htimestamp,
518 .poll_descriptors = NULL,
519 .poll_descriptors_count = NULL,
520 .poll_revents = snd_pcm_direct_poll_revents,
524 * \brief Creates a new dsnoop PCM
525 * \param pcmp Returns created PCM handle
526 * \param name Name of PCM
527 * \param opts Direct PCM configurations
528 * \param params Parameters for slave
529 * \param root Configuration root
530 * \param sconf Slave configuration
531 * \param stream PCM Direction (stream)
532 * \param mode PCM Mode
533 * \retval zero on success otherwise a negative error code
534 * \warning Using of this function might be dangerous in the sense
535 * of compatibility reasons. The prototype might be freely
538 int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
539 struct snd_pcm_direct_open_conf *opts,
540 struct slave_params *params,
541 snd_config_t *root, snd_config_t *sconf,
542 snd_pcm_stream_t stream, int mode)
544 snd_pcm_t *pcm = NULL, *spcm = NULL;
545 snd_pcm_direct_t *dsnoop = NULL;
546 int ret, first_instance, fail_sem_loop = 10;
550 if (stream != SND_PCM_STREAM_CAPTURE) {
551 SNDERR("The dsnoop plugin supports only capture stream");
555 dsnoop = calloc(1, sizeof(snd_pcm_direct_t));
561 ret = snd_pcm_direct_parse_bindings(dsnoop, params, opts->bindings);
565 dsnoop->ipc_key = opts->ipc_key;
566 dsnoop->ipc_perm = opts->ipc_perm;
567 dsnoop->ipc_gid = opts->ipc_gid;
571 ret = snd_pcm_new(&pcm, dsnoop->type = SND_PCM_TYPE_DSNOOP, name, stream, mode);
576 ret = snd_pcm_direct_semaphore_create_or_connect(dsnoop);
578 SNDERR("unable to create IPC semaphore");
582 ret = snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
584 snd_pcm_direct_semaphore_discard(dsnoop);
585 if (--fail_sem_loop <= 0)
592 first_instance = ret = snd_pcm_direct_shm_create_or_connect(dsnoop);
594 SNDERR("unable to create IPC shm instance");
598 pcm->ops = &snd_pcm_dsnoop_ops;
599 pcm->fast_ops = &snd_pcm_dsnoop_fast_ops;
600 pcm->private_data = dsnoop;
601 dsnoop->state = SND_PCM_STATE_OPEN;
602 dsnoop->slowptr = opts->slowptr;
603 dsnoop->max_periods = opts->max_periods;
604 dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr;
606 if (first_instance) {
607 /* recursion is already checked in
608 snd_pcm_direct_get_slave_ipc_offset() */
609 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
610 mode | SND_PCM_NONBLOCK, NULL);
612 SNDERR("unable to open slave");
616 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
617 SNDERR("dsnoop plugin can be only connected to hw plugin");
621 ret = snd_pcm_direct_initialize_slave(dsnoop, spcm, params);
623 SNDERR("unable to initialize slave");
629 if (dsnoop->shmptr->use_server) {
630 ret = snd_pcm_direct_server_create(dsnoop);
632 SNDERR("unable to create server");
637 dsnoop->shmptr->type = spcm->type;
639 if (dsnoop->shmptr->use_server) {
640 /* up semaphore to avoid deadlock */
641 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
642 ret = snd_pcm_direct_client_connect(dsnoop);
644 SNDERR("unable to connect client");
648 snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
650 ret = snd_pcm_direct_open_secondary_client(&spcm, dsnoop, "dsnoop_client");
655 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
656 mode | SND_PCM_NONBLOCK |
660 SNDERR("unable to open slave");
663 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
664 SNDERR("dsnoop plugin can be only connected to hw plugin");
669 ret = snd_pcm_direct_initialize_secondary_slave(dsnoop, spcm, params);
671 SNDERR("unable to initialize slave");
679 ret = snd_pcm_direct_initialize_poll_fd(dsnoop);
681 SNDERR("unable to initialize poll_fd");
685 pcm->poll_fd = dsnoop->poll_fd;
686 pcm->poll_events = POLLIN; /* it's different than other plugins */
689 snd_pcm_set_hw_ptr(pcm, &dsnoop->hw_ptr, -1, 0);
690 snd_pcm_set_appl_ptr(pcm, &dsnoop->appl_ptr, -1, 0);
692 if (dsnoop->channels == UINT_MAX)
693 dsnoop->channels = dsnoop->shmptr->s.channels;
695 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
702 snd_timer_close(dsnoop->timer);
704 snd_pcm_direct_server_discard(dsnoop);
706 snd_pcm_direct_client_discard(dsnoop);
709 if (dsnoop->shmid >= 0)
710 snd_pcm_direct_shm_discard(dsnoop);
711 if (snd_pcm_direct_semaphore_discard(dsnoop) < 0)
712 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
715 free(dsnoop->bindings);
723 /*! \page pcm_plugins
725 \section pcm_plugins_dsnoop Plugin: dsnoop
727 This plugin splits one capture stream to more.
728 It works the reverse way of \ref pcm_plugins_dmix "dmix plugin",
729 reading the shared capture buffer from many clients concurrently.
730 The meaning of parameters below are almost identical with
735 type dsnoop # Direct snoop
736 ipc_key INT # unique IPC key
737 ipc_key_add_uid BOOL # add current uid to unique IPC key
738 ipc_perm INT # IPC permissions (octal, default 0600)
741 slave { # Slave definition
742 pcm STR # slave PCM name
744 pcm { } # slave PCM definition
745 format STR # format definition
746 rate INT # rate definition
748 period_time INT # in usec
750 period_size INT # in bytes
751 buffer_time INT # in usec
753 buffer_size INT # in bytes
754 periods INT # when buffer_size or buffer_time is not specified
756 bindings { # note: this is client independent!!!
757 N INT # maps slave channel to client channel N
759 slowptr BOOL # slow but more precise pointer updates
763 \subsection pcm_plugins_dsnoop_funcref Function reference
766 <LI>snd_pcm_dsnoop_open()
767 <LI>_snd_pcm_dsnoop_open()
773 * \brief Creates a new dsnoop PCM
774 * \param pcmp Returns created PCM handle
775 * \param name Name of PCM
776 * \param root Root configuration node
777 * \param conf Configuration node with dsnoop PCM description
778 * \param stream PCM Stream
779 * \param mode PCM Mode
780 * \warning Using of this function might be dangerous in the sense
781 * of compatibility reasons. The prototype might be freely
784 int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
785 snd_config_t *root, snd_config_t *conf,
786 snd_pcm_stream_t stream, int mode)
789 struct slave_params params;
790 struct snd_pcm_direct_open_conf dopen;
794 err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
798 /* the default settings, it might be invalid for some hardware */
799 params.format = SND_PCM_FORMAT_S16;
802 params.period_time = -1;
803 params.buffer_time = -1;
806 err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
807 SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format,
808 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
809 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
810 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
811 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
812 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
813 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
814 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
818 /* set a reasonable default */
819 if (psize == -1 && params.period_time == -1)
820 params.period_time = 125000; /* 0.125 seconds */
822 if (params.format == -2)
823 params.format = SND_PCM_FORMAT_UNKNOWN;
825 params.period_size = psize;
826 params.buffer_size = bsize;
828 err = snd_pcm_dsnoop_open(pcmp, name, &dopen, ¶ms,
829 root, sconf, stream, mode);
830 snd_config_delete(sconf);
834 SND_DLSYM_BUILD_VERSION(_snd_pcm_dsnoop_open, SND_PCM_DLSYM_VERSION);