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 = slave_hw_ptr - old_slave_hw_ptr;
156 if (diff == 0) /* fast path */
159 slave_hw_ptr += dsnoop->slave_boundary;
160 diff = slave_hw_ptr - old_slave_hw_ptr;
162 snd_pcm_dsnoop_sync_area(pcm, old_slave_hw_ptr, diff);
163 dsnoop->hw_ptr += diff;
164 dsnoop->hw_ptr %= pcm->boundary;
165 // printf("sync ptr diff = %li\n", diff);
166 if (pcm->stop_threshold >= pcm->boundary) /* don't care */
168 if ((avail = snd_pcm_mmap_capture_hw_avail(pcm)) >= pcm->stop_threshold) {
169 gettimestamp(&dsnoop->trigger_tstamp, pcm->tstamp_type);
170 dsnoop->state = SND_PCM_STATE_XRUN;
171 dsnoop->avail_max = avail;
174 if (avail > dsnoop->avail_max)
175 dsnoop->avail_max = avail;
180 * plugin implementation
183 static int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
185 snd_pcm_direct_t *dsnoop = pcm->private_data;
186 snd_pcm_state_t state;
188 switch(dsnoop->state) {
189 case SNDRV_PCM_STATE_DRAINING:
190 case SNDRV_PCM_STATE_RUNNING:
191 snd_pcm_dsnoop_sync_ptr(pcm);
196 memset(status, 0, sizeof(*status));
197 snd_pcm_status(dsnoop->spcm, status);
198 state = snd_pcm_state(dsnoop->spcm);
199 status->state = state == SND_PCM_STATE_RUNNING ? dsnoop->state : state;
200 status->trigger_tstamp = dsnoop->trigger_tstamp;
201 status->avail = snd_pcm_mmap_capture_avail(pcm);
202 status->avail_max = status->avail > dsnoop->avail_max ? status->avail : dsnoop->avail_max;
203 dsnoop->avail_max = 0;
204 status->delay = snd_pcm_mmap_capture_delay(pcm);
208 static snd_pcm_state_t snd_pcm_dsnoop_state(snd_pcm_t *pcm)
210 snd_pcm_direct_t *dsnoop = pcm->private_data;
212 snd_pcm_state_t state;
213 state = snd_pcm_state(dsnoop->spcm);
215 case SND_PCM_STATE_SUSPENDED:
216 case SND_PCM_STATE_DISCONNECTED:
217 dsnoop->state = state;
219 case SND_PCM_STATE_XRUN:
220 if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0)
226 snd_pcm_direct_client_chk_xrun(dsnoop, pcm);
227 return dsnoop->state;
230 static int snd_pcm_dsnoop_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
232 snd_pcm_direct_t *dsnoop = pcm->private_data;
235 switch(dsnoop->state) {
236 case SNDRV_PCM_STATE_DRAINING:
237 case SNDRV_PCM_STATE_RUNNING:
238 err = snd_pcm_dsnoop_sync_ptr(pcm);
242 case SNDRV_PCM_STATE_PREPARED:
243 case SNDRV_PCM_STATE_SUSPENDED:
244 *delayp = snd_pcm_mmap_capture_hw_avail(pcm);
246 case SNDRV_PCM_STATE_XRUN:
248 case SNDRV_PCM_STATE_DISCONNECTED:
255 static int snd_pcm_dsnoop_hwsync(snd_pcm_t *pcm)
257 snd_pcm_direct_t *dsnoop = pcm->private_data;
259 switch(dsnoop->state) {
260 case SNDRV_PCM_STATE_DRAINING:
261 case SNDRV_PCM_STATE_RUNNING:
262 return snd_pcm_dsnoop_sync_ptr(pcm);
263 case SNDRV_PCM_STATE_PREPARED:
264 case SNDRV_PCM_STATE_SUSPENDED:
266 case SNDRV_PCM_STATE_XRUN:
268 case SNDRV_PCM_STATE_DISCONNECTED:
275 static int snd_pcm_dsnoop_reset(snd_pcm_t *pcm)
277 snd_pcm_direct_t *dsnoop = pcm->private_data;
278 dsnoop->hw_ptr %= pcm->period_size;
279 dsnoop->appl_ptr = dsnoop->hw_ptr;
280 dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr;
284 static int snd_pcm_dsnoop_start(snd_pcm_t *pcm)
286 snd_pcm_direct_t *dsnoop = pcm->private_data;
289 if (dsnoop->state != SND_PCM_STATE_PREPARED)
291 snd_pcm_hwsync(dsnoop->spcm);
292 snoop_timestamp(pcm);
293 dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr;
294 err = snd_timer_start(dsnoop->timer);
297 dsnoop->state = SND_PCM_STATE_RUNNING;
298 dsnoop->trigger_tstamp = dsnoop->update_tstamp;
302 static int snd_pcm_dsnoop_drop(snd_pcm_t *pcm)
304 snd_pcm_direct_t *dsnoop = pcm->private_data;
305 if (dsnoop->state == SND_PCM_STATE_OPEN)
307 dsnoop->state = SND_PCM_STATE_SETUP;
308 snd_timer_stop(dsnoop->timer);
313 static int __snd_pcm_dsnoop_drain(snd_pcm_t *pcm)
315 snd_pcm_direct_t *dsnoop = pcm->private_data;
316 snd_pcm_uframes_t stop_threshold;
319 if (dsnoop->state == SND_PCM_STATE_OPEN)
321 stop_threshold = pcm->stop_threshold;
322 if (pcm->stop_threshold > pcm->buffer_size)
323 pcm->stop_threshold = pcm->buffer_size;
324 while (dsnoop->state == SND_PCM_STATE_RUNNING) {
325 err = snd_pcm_dsnoop_sync_ptr(pcm);
328 if (pcm->mode & SND_PCM_NONBLOCK)
330 __snd_pcm_wait_in_lock(pcm, -1);
332 pcm->stop_threshold = stop_threshold;
333 return snd_pcm_dsnoop_drop(pcm);
336 static int snd_pcm_dsnoop_drain(snd_pcm_t *pcm)
341 err = __snd_pcm_dsnoop_drain(pcm);
346 static int snd_pcm_dsnoop_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
351 static snd_pcm_sframes_t snd_pcm_dsnoop_rewindable(snd_pcm_t *pcm)
353 return snd_pcm_mmap_capture_hw_avail(pcm);
356 static snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
358 snd_pcm_sframes_t avail;
360 avail = snd_pcm_dsnoop_rewindable(pcm);
361 if (frames > (snd_pcm_uframes_t)avail)
363 snd_pcm_mmap_appl_backward(pcm, frames);
367 static snd_pcm_sframes_t snd_pcm_dsnoop_forwardable(snd_pcm_t *pcm)
369 return snd_pcm_mmap_capture_avail(pcm);
372 static snd_pcm_sframes_t snd_pcm_dsnoop_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
374 snd_pcm_sframes_t avail;
376 avail = snd_pcm_dsnoop_forwardable(pcm);
377 if (frames > (snd_pcm_uframes_t)avail)
379 snd_pcm_mmap_appl_forward(pcm, frames);
383 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)
388 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)
393 static int snd_pcm_dsnoop_close(snd_pcm_t *pcm)
395 snd_pcm_direct_t *dsnoop = pcm->private_data;
398 snd_timer_close(dsnoop->timer);
399 snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
400 snd_pcm_close(dsnoop->spcm);
402 snd_pcm_direct_server_discard(dsnoop);
404 snd_pcm_direct_client_discard(dsnoop);
405 if (snd_pcm_direct_shm_discard(dsnoop)) {
406 if (snd_pcm_direct_semaphore_discard(dsnoop))
407 snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT);
409 snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT);
410 free(dsnoop->bindings);
411 pcm->private_data = NULL;
416 static snd_pcm_sframes_t snd_pcm_dsnoop_mmap_commit(snd_pcm_t *pcm,
417 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
418 snd_pcm_uframes_t size)
420 snd_pcm_direct_t *dsnoop = pcm->private_data;
423 switch (snd_pcm_state(dsnoop->spcm)) {
424 case SND_PCM_STATE_XRUN:
425 if ((err = snd_pcm_direct_slave_recover(dsnoop)) < 0)
428 case SND_PCM_STATE_SUSPENDED:
433 if (snd_pcm_direct_client_chk_xrun(dsnoop, pcm))
435 if (dsnoop->state == SND_PCM_STATE_RUNNING) {
436 err = snd_pcm_dsnoop_sync_ptr(pcm);
440 snd_pcm_mmap_appl_forward(pcm, size);
441 /* clear timer queue to avoid a bogus return from poll */
442 if (snd_pcm_mmap_capture_avail(pcm) < pcm->avail_min)
443 snd_pcm_direct_clear_timer_queue(dsnoop);
447 static snd_pcm_sframes_t snd_pcm_dsnoop_avail_update(snd_pcm_t *pcm)
449 snd_pcm_direct_t *dsnoop = pcm->private_data;
452 if (dsnoop->state == SND_PCM_STATE_RUNNING) {
453 err = snd_pcm_dsnoop_sync_ptr(pcm);
457 if (dsnoop->state == SND_PCM_STATE_XRUN)
460 return snd_pcm_mmap_capture_avail(pcm);
463 static int snd_pcm_dsnoop_htimestamp(snd_pcm_t *pcm,
464 snd_pcm_uframes_t *avail,
465 snd_htimestamp_t *tstamp)
467 snd_pcm_direct_t *dsnoop = pcm->private_data;
468 snd_pcm_uframes_t avail1;
472 if (dsnoop->state == SND_PCM_STATE_RUNNING ||
473 dsnoop->state == SND_PCM_STATE_DRAINING)
474 snd_pcm_dsnoop_sync_ptr(pcm);
475 avail1 = snd_pcm_mmap_capture_avail(pcm);
476 if (ok && *avail == avail1)
479 *tstamp = snd_pcm_hw_fast_tstamp(dsnoop->spcm);
485 static void snd_pcm_dsnoop_dump(snd_pcm_t *pcm, snd_output_t *out)
487 snd_pcm_direct_t *dsnoop = pcm->private_data;
489 snd_output_printf(out, "Direct Snoop PCM\n");
491 snd_output_printf(out, "Its setup is:\n");
492 snd_pcm_dump_setup(pcm, out);
495 snd_pcm_dump(dsnoop->spcm, out);
498 static const snd_pcm_ops_t snd_pcm_dsnoop_ops = {
499 .close = snd_pcm_dsnoop_close,
500 .info = snd_pcm_direct_info,
501 .hw_refine = snd_pcm_direct_hw_refine,
502 .hw_params = snd_pcm_direct_hw_params,
503 .hw_free = snd_pcm_direct_hw_free,
504 .sw_params = snd_pcm_direct_sw_params,
505 .channel_info = snd_pcm_direct_channel_info,
506 .dump = snd_pcm_dsnoop_dump,
507 .nonblock = snd_pcm_direct_nonblock,
508 .async = snd_pcm_direct_async,
509 .mmap = snd_pcm_direct_mmap,
510 .munmap = snd_pcm_direct_munmap,
511 .query_chmaps = snd_pcm_direct_query_chmaps,
512 .get_chmap = snd_pcm_direct_get_chmap,
513 .set_chmap = snd_pcm_direct_set_chmap,
516 static const snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = {
517 .status = snd_pcm_dsnoop_status,
518 .state = snd_pcm_dsnoop_state,
519 .hwsync = snd_pcm_dsnoop_hwsync,
520 .delay = snd_pcm_dsnoop_delay,
521 .prepare = snd_pcm_direct_prepare,
522 .reset = snd_pcm_dsnoop_reset,
523 .start = snd_pcm_dsnoop_start,
524 .drop = snd_pcm_dsnoop_drop,
525 .drain = snd_pcm_dsnoop_drain,
526 .pause = snd_pcm_dsnoop_pause,
527 .rewindable = snd_pcm_dsnoop_rewindable,
528 .rewind = snd_pcm_dsnoop_rewind,
529 .forwardable = snd_pcm_dsnoop_forwardable,
530 .forward = snd_pcm_dsnoop_forward,
531 .resume = snd_pcm_direct_resume,
535 .writei = snd_pcm_dsnoop_writei,
536 .writen = snd_pcm_dsnoop_writen,
537 .readi = snd_pcm_mmap_readi,
538 .readn = snd_pcm_mmap_readn,
539 .avail_update = snd_pcm_dsnoop_avail_update,
540 .mmap_commit = snd_pcm_dsnoop_mmap_commit,
541 .htimestamp = snd_pcm_dsnoop_htimestamp,
542 .poll_descriptors = snd_pcm_direct_poll_descriptors,
543 .poll_descriptors_count = NULL,
544 .poll_revents = snd_pcm_direct_poll_revents,
548 * \brief Creates a new dsnoop PCM
549 * \param pcmp Returns created PCM handle
550 * \param name Name of PCM
551 * \param opts Direct PCM configurations
552 * \param params Parameters for slave
553 * \param root Configuration root
554 * \param sconf Slave configuration
555 * \param stream PCM Direction (stream)
556 * \param mode PCM Mode
557 * \retval zero on success otherwise a negative error code
558 * \warning Using of this function might be dangerous in the sense
559 * of compatibility reasons. The prototype might be freely
562 int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
563 struct snd_pcm_direct_open_conf *opts,
564 struct slave_params *params,
565 snd_config_t *root, snd_config_t *sconf,
566 snd_pcm_stream_t stream, int mode)
568 snd_pcm_t *pcm = NULL, *spcm = NULL;
569 snd_pcm_direct_t *dsnoop = NULL;
570 int ret, first_instance, fail_sem_loop = 10;
574 if (stream != SND_PCM_STREAM_CAPTURE) {
575 SNDERR("The dsnoop plugin supports only capture stream");
579 dsnoop = calloc(1, sizeof(snd_pcm_direct_t));
585 ret = snd_pcm_direct_parse_bindings(dsnoop, params, opts->bindings);
589 dsnoop->ipc_key = opts->ipc_key;
590 dsnoop->ipc_perm = opts->ipc_perm;
591 dsnoop->ipc_gid = opts->ipc_gid;
595 ret = snd_pcm_new(&pcm, dsnoop->type = SND_PCM_TYPE_DSNOOP, name, stream, mode);
600 ret = snd_pcm_direct_semaphore_create_or_connect(dsnoop);
602 SNDERR("unable to create IPC semaphore");
606 ret = snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
608 snd_pcm_direct_semaphore_discard(dsnoop);
609 if (--fail_sem_loop <= 0)
616 first_instance = ret = snd_pcm_direct_shm_create_or_connect(dsnoop);
618 SNDERR("unable to create IPC shm instance");
622 pcm->ops = &snd_pcm_dsnoop_ops;
623 pcm->fast_ops = &snd_pcm_dsnoop_fast_ops;
624 pcm->private_data = dsnoop;
625 dsnoop->state = SND_PCM_STATE_OPEN;
626 dsnoop->slowptr = opts->slowptr;
627 dsnoop->max_periods = opts->max_periods;
628 dsnoop->var_periodsize = opts->var_periodsize;
629 dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr;
632 if (first_instance) {
633 /* recursion is already checked in
634 snd_pcm_direct_get_slave_ipc_offset() */
635 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
636 mode | SND_PCM_NONBLOCK, NULL);
638 SNDERR("unable to open slave");
642 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
643 SNDERR("dsnoop plugin can be only connected to hw plugin");
647 ret = snd_pcm_direct_initialize_slave(dsnoop, spcm, params);
649 SNDERR("unable to initialize slave");
655 if (dsnoop->shmptr->use_server) {
656 ret = snd_pcm_direct_server_create(dsnoop);
658 SNDERR("unable to create server");
663 dsnoop->shmptr->type = spcm->type;
665 if (dsnoop->shmptr->use_server) {
666 /* up semaphore to avoid deadlock */
667 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
668 ret = snd_pcm_direct_client_connect(dsnoop);
670 SNDERR("unable to connect client");
674 snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
676 ret = snd_pcm_direct_open_secondary_client(&spcm, dsnoop, "dsnoop_client");
681 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
682 mode | SND_PCM_NONBLOCK |
686 /* all other streams have been closed;
687 * retry as the first instance
689 if (ret == -EBADFD) {
693 SNDERR("unable to open slave");
696 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
697 SNDERR("dsnoop plugin can be only connected to hw plugin");
702 ret = snd_pcm_direct_initialize_secondary_slave(dsnoop, spcm, params);
704 SNDERR("unable to initialize slave");
712 ret = snd_pcm_direct_initialize_poll_fd(dsnoop);
714 SNDERR("unable to initialize poll_fd");
718 pcm->poll_fd = dsnoop->poll_fd;
719 pcm->poll_events = POLLIN; /* it's different than other plugins */
720 pcm->tstamp_type = spcm->tstamp_type;
722 snd_pcm_set_hw_ptr(pcm, &dsnoop->hw_ptr, -1, 0);
723 snd_pcm_set_appl_ptr(pcm, &dsnoop->appl_ptr, -1, 0);
725 if (dsnoop->channels == UINT_MAX)
726 dsnoop->channels = dsnoop->shmptr->s.channels;
728 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
735 snd_timer_close(dsnoop->timer);
737 snd_pcm_direct_server_discard(dsnoop);
739 snd_pcm_direct_client_discard(dsnoop);
742 if ((dsnoop->shmid >= 0) && (snd_pcm_direct_shm_discard(dsnoop))) {
743 if (snd_pcm_direct_semaphore_discard(dsnoop))
744 snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT);
746 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
750 free(dsnoop->bindings);
758 /*! \page pcm_plugins
760 \section pcm_plugins_dsnoop Plugin: dsnoop
762 This plugin splits one capture stream to more.
763 It works the reverse way of \ref pcm_plugins_dmix "dmix plugin",
764 reading the shared capture buffer from many clients concurrently.
765 The meaning of parameters below are almost identical with
770 type dsnoop # Direct snoop
771 ipc_key INT # unique IPC key
772 ipc_key_add_uid BOOL # add current uid to unique IPC key
773 ipc_perm INT # IPC permissions (octal, default 0600)
776 slave { # Slave definition
777 pcm STR # slave PCM name
779 pcm { } # slave PCM definition
780 format STR # format definition
781 rate INT # rate definition
783 period_time INT # in usec
785 period_size INT # in bytes
786 buffer_time INT # in usec
788 buffer_size INT # in bytes
789 periods INT # when buffer_size or buffer_time is not specified
791 bindings { # note: this is client independent!!!
792 N INT # maps slave channel to client channel N
794 slowptr BOOL # slow but more precise pointer updates
798 \subsection pcm_plugins_dsnoop_funcref Function reference
801 <LI>snd_pcm_dsnoop_open()
802 <LI>_snd_pcm_dsnoop_open()
808 * \brief Creates a new dsnoop PCM
809 * \param pcmp Returns created PCM handle
810 * \param name Name of PCM
811 * \param root Root configuration node
812 * \param conf Configuration node with dsnoop PCM description
813 * \param stream PCM Stream
814 * \param mode PCM Mode
815 * \warning Using of this function might be dangerous in the sense
816 * of compatibility reasons. The prototype might be freely
819 int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
820 snd_config_t *root, snd_config_t *conf,
821 snd_pcm_stream_t stream, int mode)
824 struct slave_params params;
825 struct snd_pcm_direct_open_conf dopen;
829 err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
833 /* the default settings, it might be invalid for some hardware */
834 params.format = SND_PCM_FORMAT_S16;
837 params.period_time = -1;
838 params.buffer_time = -1;
841 err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
842 SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format,
843 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
844 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
845 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
846 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
847 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
848 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
849 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
853 /* set a reasonable default */
854 if (psize == -1 && params.period_time == -1)
855 params.period_time = 125000; /* 0.125 seconds */
857 if (params.format == -2)
858 params.format = SND_PCM_FORMAT_UNKNOWN;
860 params.period_size = psize;
861 params.buffer_size = bsize;
863 err = snd_pcm_dsnoop_open(pcmp, name, &dopen, ¶ms,
864 root, sconf, stream, mode);
865 snd_config_delete(sconf);
869 SND_DLSYM_BUILD_VERSION(_snd_pcm_dsnoop_open, SND_PCM_DLSYM_VERSION);