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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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;
137 switch (snd_pcm_state(dsnoop->spcm)) {
138 case SND_PCM_STATE_DISCONNECTED:
139 dsnoop->state = SNDRV_PCM_STATE_DISCONNECTED;
141 case SND_PCM_STATE_XRUN:
142 if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0)
148 if (snd_pcm_direct_client_chk_xrun(dsnoop, pcm))
151 snd_pcm_hwsync(dsnoop->spcm);
152 old_slave_hw_ptr = dsnoop->slave_hw_ptr;
153 snoop_timestamp(pcm);
154 slave_hw_ptr = dsnoop->slave_hw_ptr;
155 diff = pcm_frame_diff(slave_hw_ptr, old_slave_hw_ptr, dsnoop->slave_boundary);
156 if (diff == 0) /* fast path */
158 snd_pcm_dsnoop_sync_area(pcm, old_slave_hw_ptr, diff);
159 dsnoop->hw_ptr += diff;
160 dsnoop->hw_ptr %= pcm->boundary;
161 // printf("sync ptr diff = %li\n", diff);
162 if (pcm->stop_threshold >= pcm->boundary) /* don't care */
164 if ((avail = snd_pcm_mmap_capture_avail(pcm)) >= pcm->stop_threshold) {
165 gettimestamp(&dsnoop->trigger_tstamp, pcm->tstamp_type);
166 dsnoop->state = SND_PCM_STATE_XRUN;
167 dsnoop->avail_max = avail;
170 if (avail > dsnoop->avail_max)
171 dsnoop->avail_max = avail;
176 * plugin implementation
179 static int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
181 snd_pcm_direct_t *dsnoop = pcm->private_data;
182 snd_pcm_state_t state;
184 switch(dsnoop->state) {
185 case SNDRV_PCM_STATE_DRAINING:
186 case SNDRV_PCM_STATE_RUNNING:
187 snd_pcm_dsnoop_sync_ptr(pcm);
192 memset(status, 0, sizeof(*status));
193 snd_pcm_status(dsnoop->spcm, status);
194 state = snd_pcm_state(dsnoop->spcm);
195 status->state = state == SND_PCM_STATE_RUNNING ? dsnoop->state : state;
196 status->appl_ptr = *pcm->appl.ptr; /* slave PCM doesn't set appl_ptr */
197 status->trigger_tstamp = dsnoop->trigger_tstamp;
198 status->avail = snd_pcm_mmap_capture_avail(pcm);
199 status->avail_max = status->avail > dsnoop->avail_max ? status->avail : dsnoop->avail_max;
200 dsnoop->avail_max = 0;
201 status->delay = snd_pcm_mmap_capture_delay(pcm);
205 static snd_pcm_state_t snd_pcm_dsnoop_state(snd_pcm_t *pcm)
207 snd_pcm_direct_t *dsnoop = pcm->private_data;
209 snd_pcm_state_t state;
210 state = snd_pcm_state(dsnoop->spcm);
212 case SND_PCM_STATE_SUSPENDED:
213 case SND_PCM_STATE_DISCONNECTED:
214 dsnoop->state = state;
216 case SND_PCM_STATE_XRUN:
217 if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0)
223 snd_pcm_direct_client_chk_xrun(dsnoop, pcm);
224 return dsnoop->state;
227 static int snd_pcm_dsnoop_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
229 snd_pcm_direct_t *dsnoop = pcm->private_data;
232 switch(dsnoop->state) {
233 case SNDRV_PCM_STATE_DRAINING:
234 case SNDRV_PCM_STATE_RUNNING:
235 err = snd_pcm_dsnoop_sync_ptr(pcm);
239 case SNDRV_PCM_STATE_PREPARED:
240 case SNDRV_PCM_STATE_SUSPENDED:
241 *delayp = snd_pcm_mmap_capture_avail(pcm);
243 case SNDRV_PCM_STATE_XRUN:
245 case SNDRV_PCM_STATE_DISCONNECTED:
252 static int snd_pcm_dsnoop_hwsync(snd_pcm_t *pcm)
254 snd_pcm_direct_t *dsnoop = pcm->private_data;
256 switch(dsnoop->state) {
257 case SNDRV_PCM_STATE_DRAINING:
258 case SNDRV_PCM_STATE_RUNNING:
259 return snd_pcm_dsnoop_sync_ptr(pcm);
260 case SNDRV_PCM_STATE_PREPARED:
261 case SNDRV_PCM_STATE_SUSPENDED:
263 case SNDRV_PCM_STATE_XRUN:
265 case SNDRV_PCM_STATE_DISCONNECTED:
272 static int snd_pcm_dsnoop_reset(snd_pcm_t *pcm)
274 snd_pcm_direct_t *dsnoop = pcm->private_data;
275 dsnoop->hw_ptr %= pcm->period_size;
276 dsnoop->appl_ptr = dsnoop->hw_ptr;
277 dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr;
278 snd_pcm_direct_reset_slave_ptr(pcm, dsnoop);
282 static int snd_pcm_dsnoop_start(snd_pcm_t *pcm)
284 snd_pcm_direct_t *dsnoop = pcm->private_data;
287 if (dsnoop->state != SND_PCM_STATE_PREPARED)
289 snd_pcm_hwsync(dsnoop->spcm);
290 snoop_timestamp(pcm);
291 dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr;
292 snd_pcm_direct_reset_slave_ptr(pcm, dsnoop);
293 err = snd_timer_start(dsnoop->timer);
296 dsnoop->state = SND_PCM_STATE_RUNNING;
297 dsnoop->trigger_tstamp = dsnoop->update_tstamp;
301 static int snd_pcm_dsnoop_drop(snd_pcm_t *pcm)
303 snd_pcm_direct_t *dsnoop = pcm->private_data;
304 if (dsnoop->state == SND_PCM_STATE_OPEN)
306 dsnoop->state = SND_PCM_STATE_SETUP;
307 snd_timer_stop(dsnoop->timer);
312 static int __snd_pcm_dsnoop_drain(snd_pcm_t *pcm)
314 snd_pcm_direct_t *dsnoop = pcm->private_data;
315 snd_pcm_uframes_t stop_threshold;
318 if (dsnoop->state == SND_PCM_STATE_OPEN)
320 stop_threshold = pcm->stop_threshold;
321 if (pcm->stop_threshold > pcm->buffer_size)
322 pcm->stop_threshold = pcm->buffer_size;
323 while (dsnoop->state == SND_PCM_STATE_RUNNING) {
324 err = snd_pcm_dsnoop_sync_ptr(pcm);
327 if (pcm->mode & SND_PCM_NONBLOCK)
329 __snd_pcm_wait_in_lock(pcm, -1);
331 pcm->stop_threshold = stop_threshold;
332 return snd_pcm_dsnoop_drop(pcm);
335 static int snd_pcm_dsnoop_drain(snd_pcm_t *pcm)
340 err = __snd_pcm_dsnoop_drain(pcm);
345 static int snd_pcm_dsnoop_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
350 static snd_pcm_sframes_t snd_pcm_dsnoop_rewindable(snd_pcm_t *pcm)
352 return snd_pcm_mmap_capture_hw_rewindable(pcm);
355 static snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
357 snd_pcm_sframes_t avail;
359 avail = snd_pcm_dsnoop_rewindable(pcm);
360 if (frames > (snd_pcm_uframes_t)avail)
362 snd_pcm_mmap_appl_backward(pcm, frames);
366 static snd_pcm_sframes_t snd_pcm_dsnoop_forwardable(snd_pcm_t *pcm)
368 return snd_pcm_mmap_capture_avail(pcm);
371 static snd_pcm_sframes_t snd_pcm_dsnoop_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
373 snd_pcm_sframes_t avail;
375 avail = snd_pcm_dsnoop_forwardable(pcm);
376 if (frames > (snd_pcm_uframes_t)avail)
378 snd_pcm_mmap_appl_forward(pcm, frames);
382 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)
387 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)
392 static int snd_pcm_dsnoop_close(snd_pcm_t *pcm)
394 snd_pcm_direct_t *dsnoop = pcm->private_data;
397 snd_timer_close(dsnoop->timer);
398 snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
399 snd_pcm_close(dsnoop->spcm);
401 snd_pcm_direct_server_discard(dsnoop);
403 snd_pcm_direct_client_discard(dsnoop);
404 if (snd_pcm_direct_shm_discard(dsnoop)) {
405 if (snd_pcm_direct_semaphore_discard(dsnoop))
406 snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT);
408 snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT);
409 free(dsnoop->bindings);
410 pcm->private_data = NULL;
415 static snd_pcm_sframes_t snd_pcm_dsnoop_mmap_commit(snd_pcm_t *pcm,
416 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
417 snd_pcm_uframes_t size)
419 snd_pcm_direct_t *dsnoop = pcm->private_data;
422 switch (snd_pcm_state(dsnoop->spcm)) {
423 case SND_PCM_STATE_XRUN:
424 if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0)
427 case SND_PCM_STATE_SUSPENDED:
432 if (snd_pcm_direct_client_chk_xrun(dsnoop, pcm))
434 if (dsnoop->state == SND_PCM_STATE_RUNNING) {
435 err = snd_pcm_dsnoop_sync_ptr(pcm);
439 snd_pcm_mmap_appl_forward(pcm, size);
440 /* clear timer queue to avoid a bogus return from poll */
441 if (snd_pcm_mmap_capture_avail(pcm) < pcm->avail_min)
442 snd_pcm_direct_clear_timer_queue(dsnoop);
446 static snd_pcm_sframes_t snd_pcm_dsnoop_avail_update(snd_pcm_t *pcm)
448 snd_pcm_direct_t *dsnoop = pcm->private_data;
451 if (dsnoop->state == SND_PCM_STATE_RUNNING) {
452 err = snd_pcm_dsnoop_sync_ptr(pcm);
456 if (dsnoop->state == SND_PCM_STATE_XRUN)
459 return snd_pcm_mmap_capture_avail(pcm);
462 static int snd_pcm_dsnoop_htimestamp(snd_pcm_t *pcm,
463 snd_pcm_uframes_t *avail,
464 snd_htimestamp_t *tstamp)
466 snd_pcm_direct_t *dsnoop = pcm->private_data;
467 snd_pcm_uframes_t avail1;
471 if (dsnoop->state == SND_PCM_STATE_RUNNING ||
472 dsnoop->state == SND_PCM_STATE_DRAINING)
473 snd_pcm_dsnoop_sync_ptr(pcm);
474 avail1 = snd_pcm_mmap_capture_avail(pcm);
475 if (ok && *avail == avail1)
478 *tstamp = snd_pcm_hw_fast_tstamp(dsnoop->spcm);
484 static void snd_pcm_dsnoop_dump(snd_pcm_t *pcm, snd_output_t *out)
486 snd_pcm_direct_t *dsnoop = pcm->private_data;
488 snd_output_printf(out, "Direct Snoop PCM\n");
490 snd_output_printf(out, "Its setup is:\n");
491 snd_pcm_dump_setup(pcm, out);
494 snd_pcm_dump(dsnoop->spcm, out);
497 static const snd_pcm_ops_t snd_pcm_dsnoop_ops = {
498 .close = snd_pcm_dsnoop_close,
499 .info = snd_pcm_direct_info,
500 .hw_refine = snd_pcm_direct_hw_refine,
501 .hw_params = snd_pcm_direct_hw_params,
502 .hw_free = snd_pcm_direct_hw_free,
503 .sw_params = snd_pcm_direct_sw_params,
504 .channel_info = snd_pcm_direct_channel_info,
505 .dump = snd_pcm_dsnoop_dump,
506 .nonblock = snd_pcm_direct_nonblock,
507 .async = snd_pcm_direct_async,
508 .mmap = snd_pcm_direct_mmap,
509 .munmap = snd_pcm_direct_munmap,
510 .query_chmaps = snd_pcm_direct_query_chmaps,
511 .get_chmap = snd_pcm_direct_get_chmap,
512 .set_chmap = snd_pcm_direct_set_chmap,
515 static const snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = {
516 .status = snd_pcm_dsnoop_status,
517 .state = snd_pcm_dsnoop_state,
518 .hwsync = snd_pcm_dsnoop_hwsync,
519 .delay = snd_pcm_dsnoop_delay,
520 .prepare = snd_pcm_direct_prepare,
521 .reset = snd_pcm_dsnoop_reset,
522 .start = snd_pcm_dsnoop_start,
523 .drop = snd_pcm_dsnoop_drop,
524 .drain = snd_pcm_dsnoop_drain,
525 .pause = snd_pcm_dsnoop_pause,
526 .rewindable = snd_pcm_dsnoop_rewindable,
527 .rewind = snd_pcm_dsnoop_rewind,
528 .forwardable = snd_pcm_dsnoop_forwardable,
529 .forward = snd_pcm_dsnoop_forward,
530 .resume = snd_pcm_direct_resume,
534 .writei = snd_pcm_dsnoop_writei,
535 .writen = snd_pcm_dsnoop_writen,
536 .readi = snd_pcm_mmap_readi,
537 .readn = snd_pcm_mmap_readn,
538 .avail_update = snd_pcm_dsnoop_avail_update,
539 .mmap_commit = snd_pcm_dsnoop_mmap_commit,
540 .htimestamp = snd_pcm_dsnoop_htimestamp,
541 .poll_descriptors = snd_pcm_direct_poll_descriptors,
542 .poll_descriptors_count = NULL,
543 .poll_revents = snd_pcm_direct_poll_revents,
547 * \brief Creates a new dsnoop PCM
548 * \param pcmp Returns created PCM handle
549 * \param name Name of PCM
550 * \param opts Direct PCM configurations
551 * \param params Parameters for slave
552 * \param root Configuration root
553 * \param sconf Slave configuration
554 * \param stream PCM Direction (stream)
555 * \param mode PCM Mode
556 * \retval zero on success otherwise a negative error code
557 * \warning Using of this function might be dangerous in the sense
558 * of compatibility reasons. The prototype might be freely
561 int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
562 struct snd_pcm_direct_open_conf *opts,
563 struct slave_params *params,
564 snd_config_t *root, snd_config_t *sconf,
565 snd_pcm_stream_t stream, int mode)
567 snd_pcm_t *pcm, *spcm = NULL;
568 snd_pcm_direct_t *dsnoop;
569 int ret, first_instance;
573 if (stream != SND_PCM_STREAM_CAPTURE) {
574 SNDERR("The dsnoop plugin supports only capture stream");
578 ret = _snd_pcm_direct_new(&pcm, &dsnoop, SND_PCM_TYPE_DSNOOP, name, opts, params, stream, mode);
581 first_instance = ret;
583 pcm->ops = &snd_pcm_dsnoop_ops;
584 pcm->fast_ops = &snd_pcm_dsnoop_fast_ops;
585 pcm->private_data = dsnoop;
586 dsnoop->state = SND_PCM_STATE_OPEN;
587 dsnoop->slowptr = opts->slowptr;
588 dsnoop->max_periods = opts->max_periods;
589 dsnoop->var_periodsize = opts->var_periodsize;
590 dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr;
591 dsnoop->hw_ptr_alignment = opts->hw_ptr_alignment;
594 if (first_instance) {
595 /* recursion is already checked in
596 snd_pcm_direct_get_slave_ipc_offset() */
597 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
598 mode | SND_PCM_NONBLOCK, NULL);
600 SNDERR("unable to open slave");
604 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
605 SNDERR("dsnoop plugin can be only connected to hw plugin");
609 ret = snd_pcm_direct_initialize_slave(dsnoop, spcm, params);
611 SNDERR("unable to initialize slave");
617 if (dsnoop->shmptr->use_server) {
618 ret = snd_pcm_direct_server_create(dsnoop);
620 SNDERR("unable to create server");
625 dsnoop->shmptr->type = spcm->type;
627 if (dsnoop->shmptr->use_server) {
628 /* up semaphore to avoid deadlock */
629 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
630 ret = snd_pcm_direct_client_connect(dsnoop);
632 SNDERR("unable to connect client");
636 snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
638 ret = snd_pcm_direct_open_secondary_client(&spcm, dsnoop, "dsnoop_client");
643 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
644 mode | SND_PCM_NONBLOCK |
648 /* all other streams have been closed;
649 * retry as the first instance
651 if (ret == -EBADFD) {
655 SNDERR("unable to open slave");
658 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
659 SNDERR("dsnoop plugin can be only connected to hw plugin");
664 ret = snd_pcm_direct_initialize_secondary_slave(dsnoop, spcm, params);
666 SNDERR("unable to initialize slave");
674 ret = snd_pcm_direct_initialize_poll_fd(dsnoop);
676 SNDERR("unable to initialize poll_fd");
680 pcm->poll_fd = dsnoop->poll_fd;
681 pcm->poll_events = POLLIN; /* it's different than other plugins */
682 pcm->tstamp_type = spcm->tstamp_type;
684 snd_pcm_set_hw_ptr(pcm, &dsnoop->hw_ptr, -1, 0);
685 snd_pcm_set_appl_ptr(pcm, &dsnoop->appl_ptr, -1, 0);
687 if (dsnoop->channels == UINT_MAX)
688 dsnoop->channels = dsnoop->shmptr->s.channels;
690 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
697 snd_timer_close(dsnoop->timer);
699 snd_pcm_direct_server_discard(dsnoop);
701 snd_pcm_direct_client_discard(dsnoop);
704 if ((dsnoop->shmid >= 0) && (snd_pcm_direct_shm_discard(dsnoop))) {
705 if (snd_pcm_direct_semaphore_discard(dsnoop))
706 snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT);
708 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
711 free(dsnoop->bindings);
717 /*! \page pcm_plugins
719 \section pcm_plugins_dsnoop Plugin: dsnoop
721 This plugin splits one capture stream to more.
722 It works the reverse way of \ref pcm_plugins_dmix "dmix plugin",
723 reading the shared capture buffer from many clients concurrently.
724 The meaning of parameters below are almost identical with
729 type dsnoop # Direct snoop
730 ipc_key INT # unique IPC key
731 ipc_key_add_uid BOOL # add current uid to unique IPC key
732 ipc_perm INT # IPC permissions (octal, default 0600)
733 hw_ptr_alignment STR # Slave application and hw pointer alignment type
734 # STR can be one of the below strings :
739 tstamp_type STR # timestamp type
740 # STR can be one of the below strings :
741 # default, gettimeofday, monotonic, monotonic_raw
744 slave { # Slave definition
745 pcm STR # slave PCM name
747 pcm { } # slave PCM definition
748 format STR # format definition
749 rate INT # rate definition
751 period_time INT # in usec
753 period_size INT # in frames
754 buffer_time INT # in usec
756 buffer_size INT # in frames
757 periods INT # when buffer_size or buffer_time is not specified
759 bindings { # note: this is client independent!!!
760 N INT # maps slave channel to client channel N
762 slowptr BOOL # slow but more precise pointer updates
766 <code>hw_ptr_alignment</code> specifies slave application and hw
767 pointer alignment type. By default hw_ptr_alignment is auto. Below are
768 the possible configurations:
769 - no: minimal latency with minimal frames dropped at startup. But
770 wakeup of application (return from snd_pcm_wait() or poll()) can
771 take up to 2 * period.
772 - roundup: It is guaranteed that all frames will be played at
773 startup. But the latency will increase upto period-1 frames.
774 - rounddown: It is guaranteed that a wakeup will happen for each
775 period and frames can be written from application. But on startup
776 upto period-1 frames will be dropped.
777 - auto: Selects the best approach depending on the used period and
779 If the application buffer size is < 2 * application period,
780 "roundup" will be selected to avoid over runs. If the slave_period
781 is < 10ms we could expect that there are low latency
782 requirements. Therefore "rounddown" will be chosen to avoid long
783 wakeup times. Else "no" will be chosen.
785 \subsection pcm_plugins_dsnoop_funcref Function reference
788 <LI>snd_pcm_dsnoop_open()
789 <LI>_snd_pcm_dsnoop_open()
795 * \brief Creates a new dsnoop PCM
796 * \param pcmp Returns created PCM handle
797 * \param name Name of PCM
798 * \param root Root configuration node
799 * \param conf Configuration node with dsnoop PCM description
800 * \param stream PCM Stream
801 * \param mode PCM Mode
802 * \warning Using of this function might be dangerous in the sense
803 * of compatibility reasons. The prototype might be freely
806 int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
807 snd_config_t *root, snd_config_t *conf,
808 snd_pcm_stream_t stream, int mode)
811 struct slave_params params;
812 struct snd_pcm_direct_open_conf dopen;
816 err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
820 /* the default settings, it might be invalid for some hardware */
821 params.format = SND_PCM_FORMAT_S16;
824 params.period_time = -1;
825 params.buffer_time = -1;
828 err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
829 SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format,
830 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
831 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
832 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
833 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
834 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
835 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
836 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
840 /* set a reasonable default */
841 if (psize == -1 && params.period_time == -1)
842 params.period_time = 125000; /* 0.125 seconds */
844 if (params.format == -2)
845 params.format = SND_PCM_FORMAT_UNKNOWN;
847 params.period_size = psize;
848 params.buffer_size = bsize;
850 err = snd_pcm_dsnoop_open(pcmp, name, &dopen, ¶ms,
851 root, sconf, stream, mode);
852 snd_config_delete(sconf);
856 SND_DLSYM_BUILD_VERSION(_snd_pcm_dsnoop_open, SND_PCM_DLSYM_VERSION);