2 * \file pcm/pcm_dsnoop.c
4 * \brief PCM Capture Stream Snooping (dsnoop) Plugin Interface
5 * \author Jaroslav Kysela <perex@suse.cz>
9 * PCM - Capture Stream Snooping
10 * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.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 void snoop_areas(snd_pcm_direct_t *dsnoop,
58 const snd_pcm_channel_area_t *src_areas,
59 const snd_pcm_channel_area_t *dst_areas,
60 snd_pcm_uframes_t src_ofs,
61 snd_pcm_uframes_t dst_ofs,
62 snd_pcm_uframes_t size)
64 unsigned int chn, schn, channels;
65 snd_pcm_format_t format;
67 channels = dsnoop->channels;
68 format = dsnoop->shmptr->s.format;
69 if (dsnoop->interleaved) {
70 unsigned int fbytes = snd_pcm_format_physical_width(format) / 8;
71 memcpy(((char *)dst_areas[0].addr) + (dst_ofs * channels * fbytes),
72 ((char *)src_areas[0].addr) + (src_ofs * channels * fbytes),
73 size * channels * fbytes);
75 for (chn = 0; chn < channels; chn++) {
76 schn = dsnoop->bindings ? dsnoop->bindings[chn] : chn;
77 snd_pcm_area_copy(&dst_areas[chn], dst_ofs, &src_areas[schn], src_ofs, size, format);
83 * synchronize shm ring buffer with hardware
85 static void snd_pcm_dsnoop_sync_area(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr, snd_pcm_uframes_t size)
87 snd_pcm_direct_t *dsnoop = pcm->private_data;
88 snd_pcm_uframes_t hw_ptr = dsnoop->hw_ptr;
89 snd_pcm_uframes_t transfer;
90 const snd_pcm_channel_area_t *src_areas, *dst_areas;
92 /* add sample areas here */
93 dst_areas = snd_pcm_mmap_areas(pcm);
94 src_areas = snd_pcm_mmap_areas(dsnoop->spcm);
95 hw_ptr %= pcm->buffer_size;
96 slave_hw_ptr %= dsnoop->slave_buffer_size;
98 transfer = hw_ptr + size > pcm->buffer_size ? pcm->buffer_size - hw_ptr : size;
99 transfer = slave_hw_ptr + transfer > dsnoop->slave_buffer_size ?
100 dsnoop->slave_buffer_size - slave_hw_ptr : transfer;
102 snoop_areas(dsnoop, src_areas, dst_areas, slave_hw_ptr, hw_ptr, transfer);
103 slave_hw_ptr += transfer;
104 slave_hw_ptr %= dsnoop->slave_buffer_size;
106 hw_ptr %= pcm->buffer_size;
111 * synchronize hardware pointer (hw_ptr) with ours
113 static int snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm)
115 snd_pcm_direct_t *dsnoop = pcm->private_data;
116 snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail;
117 snd_pcm_sframes_t diff;
119 switch (snd_pcm_state(dsnoop->spcm)) {
120 case SND_PCM_STATE_DISCONNECTED:
121 dsnoop->state = SNDRV_PCM_STATE_DISCONNECTED;
127 snd_pcm_hwsync(dsnoop->spcm);
128 old_slave_hw_ptr = dsnoop->slave_hw_ptr;
129 slave_hw_ptr = dsnoop->slave_hw_ptr = *dsnoop->spcm->hw.ptr;
130 diff = slave_hw_ptr - old_slave_hw_ptr;
131 if (diff == 0) /* fast path */
134 slave_hw_ptr += dsnoop->slave_boundary;
135 diff = slave_hw_ptr - old_slave_hw_ptr;
137 snd_pcm_dsnoop_sync_area(pcm, old_slave_hw_ptr, diff);
138 dsnoop->hw_ptr += diff;
139 dsnoop->hw_ptr %= pcm->boundary;
140 // printf("sync ptr diff = %li\n", diff);
141 if (pcm->stop_threshold >= pcm->boundary) /* don't care */
143 if ((avail = snd_pcm_mmap_capture_hw_avail(pcm)) >= pcm->stop_threshold) {
145 gettimeofday(&tv, 0);
146 dsnoop->trigger_tstamp.tv_sec = tv.tv_sec;
147 dsnoop->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
148 dsnoop->state = SND_PCM_STATE_XRUN;
149 dsnoop->avail_max = avail;
152 if (avail > dsnoop->avail_max)
153 dsnoop->avail_max = avail;
158 * plugin implementation
161 static int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
163 snd_pcm_direct_t *dsnoop = pcm->private_data;
164 snd_pcm_state_t state;
166 switch(dsnoop->state) {
167 case SNDRV_PCM_STATE_DRAINING:
168 case SNDRV_PCM_STATE_RUNNING:
169 snd_pcm_dsnoop_sync_ptr(pcm);
174 memset(status, 0, sizeof(*status));
175 state = snd_pcm_state(dsnoop->spcm);
176 status->state = state == SND_PCM_STATE_RUNNING ? dsnoop->state : state;
177 status->trigger_tstamp = dsnoop->trigger_tstamp;
178 status->tstamp = snd_pcm_hw_fast_tstamp(dsnoop->spcm);
179 status->avail = snd_pcm_mmap_capture_avail(pcm);
180 status->avail_max = status->avail > dsnoop->avail_max ? status->avail : dsnoop->avail_max;
181 dsnoop->avail_max = 0;
185 static snd_pcm_state_t snd_pcm_dsnoop_state(snd_pcm_t *pcm)
187 snd_pcm_direct_t *dsnoop = pcm->private_data;
188 switch (snd_pcm_state(dsnoop->spcm)) {
189 case SND_PCM_STATE_SUSPENDED:
190 return SND_PCM_STATE_SUSPENDED;
191 case SND_PCM_STATE_DISCONNECTED:
192 dsnoop->state = SNDRV_PCM_STATE_DISCONNECTED;
197 return dsnoop->state;
200 static int snd_pcm_dsnoop_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
202 snd_pcm_direct_t *dsnoop = pcm->private_data;
205 switch(dsnoop->state) {
206 case SNDRV_PCM_STATE_DRAINING:
207 case SNDRV_PCM_STATE_RUNNING:
208 err = snd_pcm_dsnoop_sync_ptr(pcm);
211 case SNDRV_PCM_STATE_PREPARED:
212 case SNDRV_PCM_STATE_SUSPENDED:
213 *delayp = snd_pcm_mmap_capture_hw_avail(pcm);
215 case SNDRV_PCM_STATE_XRUN:
217 case SNDRV_PCM_STATE_DISCONNECTED:
224 static int snd_pcm_dsnoop_hwsync(snd_pcm_t *pcm)
226 snd_pcm_direct_t *dsnoop = pcm->private_data;
228 switch(dsnoop->state) {
229 case SNDRV_PCM_STATE_DRAINING:
230 case SNDRV_PCM_STATE_RUNNING:
231 return snd_pcm_dsnoop_sync_ptr(pcm);
232 case SNDRV_PCM_STATE_PREPARED:
233 case SNDRV_PCM_STATE_SUSPENDED:
235 case SNDRV_PCM_STATE_XRUN:
237 case SNDRV_PCM_STATE_DISCONNECTED:
244 static int snd_pcm_dsnoop_prepare(snd_pcm_t *pcm)
246 snd_pcm_direct_t *dsnoop = pcm->private_data;
248 snd_pcm_direct_check_interleave(dsnoop, pcm);
249 dsnoop->state = SND_PCM_STATE_PREPARED;
250 dsnoop->appl_ptr = 0;
252 return snd_pcm_direct_set_timer_params(dsnoop);
255 static int snd_pcm_dsnoop_reset(snd_pcm_t *pcm)
257 snd_pcm_direct_t *dsnoop = pcm->private_data;
258 dsnoop->hw_ptr %= pcm->period_size;
259 dsnoop->appl_ptr = dsnoop->hw_ptr;
260 dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr = *dsnoop->spcm->hw.ptr;
264 static int snd_pcm_dsnoop_start(snd_pcm_t *pcm)
266 snd_pcm_direct_t *dsnoop = pcm->private_data;
270 if (dsnoop->state != SND_PCM_STATE_PREPARED)
272 snd_pcm_hwsync(dsnoop->spcm);
273 dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr = *dsnoop->spcm->hw.ptr;
274 err = snd_timer_start(dsnoop->timer);
277 dsnoop->state = SND_PCM_STATE_RUNNING;
278 gettimeofday(&tv, 0);
279 dsnoop->trigger_tstamp.tv_sec = tv.tv_sec;
280 dsnoop->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
284 static int snd_pcm_dsnoop_drop(snd_pcm_t *pcm)
286 snd_pcm_direct_t *dsnoop = pcm->private_data;
287 if (dsnoop->state == SND_PCM_STATE_OPEN)
289 snd_timer_stop(dsnoop->timer);
290 dsnoop->state = SND_PCM_STATE_SETUP;
294 static int snd_pcm_dsnoop_drain(snd_pcm_t *pcm)
296 snd_pcm_direct_t *dsnoop = pcm->private_data;
297 snd_pcm_uframes_t stop_threshold;
300 if (dsnoop->state == SND_PCM_STATE_OPEN)
302 stop_threshold = pcm->stop_threshold;
303 if (pcm->stop_threshold > pcm->buffer_size)
304 pcm->stop_threshold = pcm->buffer_size;
305 while (dsnoop->state == SND_PCM_STATE_RUNNING) {
306 err = snd_pcm_dsnoop_sync_ptr(pcm);
309 if (pcm->mode & SND_PCM_NONBLOCK)
311 snd_pcm_wait(pcm, -1);
313 pcm->stop_threshold = stop_threshold;
314 return snd_pcm_dsnoop_drop(pcm);
317 static int snd_pcm_dsnoop_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
322 static snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
324 snd_pcm_mmap_appl_backward(pcm, frames);
328 static snd_pcm_sframes_t snd_pcm_dsnoop_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
330 snd_pcm_sframes_t avail;
332 avail = snd_pcm_mmap_capture_hw_avail(pcm);
335 if (frames > (snd_pcm_uframes_t)avail)
337 snd_pcm_mmap_appl_forward(pcm, frames);
341 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)
346 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)
351 static int snd_pcm_dsnoop_close(snd_pcm_t *pcm)
353 snd_pcm_direct_t *dsnoop = pcm->private_data;
356 snd_timer_close(dsnoop->timer);
357 snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
358 snd_pcm_close(dsnoop->spcm);
360 snd_pcm_direct_server_discard(dsnoop);
362 snd_pcm_direct_client_discard(dsnoop);
363 snd_pcm_direct_shm_discard(dsnoop);
364 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
365 free(dsnoop->bindings);
366 pcm->private_data = NULL;
371 static snd_pcm_sframes_t snd_pcm_dsnoop_mmap_commit(snd_pcm_t *pcm,
372 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
373 snd_pcm_uframes_t size)
375 snd_pcm_direct_t *dsnoop = pcm->private_data;
378 switch (snd_pcm_state(dsnoop->spcm)) {
379 case SND_PCM_STATE_XRUN:
381 case SND_PCM_STATE_SUSPENDED:
386 if (dsnoop->state == SND_PCM_STATE_RUNNING) {
387 err = snd_pcm_dsnoop_sync_ptr(pcm);
391 snd_pcm_mmap_appl_forward(pcm, size);
392 /* clear timer queue to avoid a bogus return from poll */
393 if (snd_pcm_mmap_capture_avail(pcm) < pcm->avail_min)
394 snd_pcm_direct_clear_timer_queue(dsnoop);
398 static snd_pcm_sframes_t snd_pcm_dsnoop_avail_update(snd_pcm_t *pcm)
400 snd_pcm_direct_t *dsnoop = pcm->private_data;
403 if (dsnoop->state == SND_PCM_STATE_RUNNING) {
404 err = snd_pcm_dsnoop_sync_ptr(pcm);
408 return snd_pcm_mmap_capture_avail(pcm);
411 static void snd_pcm_dsnoop_dump(snd_pcm_t *pcm, snd_output_t *out)
413 snd_pcm_direct_t *dsnoop = pcm->private_data;
415 snd_output_printf(out, "Direct Snoop PCM\n");
417 snd_output_printf(out, "Its setup is:\n");
418 snd_pcm_dump_setup(pcm, out);
421 snd_pcm_dump(dsnoop->spcm, out);
424 static snd_pcm_ops_t snd_pcm_dsnoop_ops = {
425 .close = snd_pcm_dsnoop_close,
426 .info = snd_pcm_direct_info,
427 .hw_refine = snd_pcm_direct_hw_refine,
428 .hw_params = snd_pcm_direct_hw_params,
429 .hw_free = snd_pcm_direct_hw_free,
430 .sw_params = snd_pcm_direct_sw_params,
431 .channel_info = snd_pcm_direct_channel_info,
432 .dump = snd_pcm_dsnoop_dump,
433 .nonblock = snd_pcm_direct_nonblock,
434 .async = snd_pcm_direct_async,
435 .mmap = snd_pcm_direct_mmap,
436 .munmap = snd_pcm_direct_munmap,
439 static snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = {
440 .status = snd_pcm_dsnoop_status,
441 .state = snd_pcm_dsnoop_state,
442 .hwsync = snd_pcm_dsnoop_hwsync,
443 .delay = snd_pcm_dsnoop_delay,
444 .prepare = snd_pcm_dsnoop_prepare,
445 .reset = snd_pcm_dsnoop_reset,
446 .start = snd_pcm_dsnoop_start,
447 .drop = snd_pcm_dsnoop_drop,
448 .drain = snd_pcm_dsnoop_drain,
449 .pause = snd_pcm_dsnoop_pause,
450 .rewind = snd_pcm_dsnoop_rewind,
451 .forward = snd_pcm_dsnoop_forward,
452 .resume = snd_pcm_direct_resume,
456 .writei = snd_pcm_dsnoop_writei,
457 .writen = snd_pcm_dsnoop_writen,
458 .readi = snd_pcm_mmap_readi,
459 .readn = snd_pcm_mmap_readn,
460 .avail_update = snd_pcm_dsnoop_avail_update,
461 .mmap_commit = snd_pcm_dsnoop_mmap_commit,
462 .poll_descriptors = NULL,
463 .poll_descriptors_count = NULL,
464 .poll_revents = snd_pcm_direct_poll_revents,
468 * \brief Creates a new dsnoop PCM
469 * \param pcmp Returns created PCM handle
470 * \param name Name of PCM
471 * \param ipc_key IPC key for semaphore and shared memory
472 * \param ipc_perm IPC permissions for semaphore and shared memory
473 * \param ipc_gid IPC group ID for semaphore and shared memory
474 * \param params Parameters for slave
475 * \param bindings Channel bindings
476 * \param slowptr Slow but more precise pointer updates
477 * \param root Configuration root
478 * \param sconf Slave configuration
479 * \param stream PCM Direction (stream)
480 * \param mode PCM Mode
481 * \retval zero on success otherwise a negative error code
482 * \warning Using of this function might be dangerous in the sense
483 * of compatibility reasons. The prototype might be freely
486 int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
487 key_t ipc_key, mode_t ipc_perm, int ipc_gid,
488 struct slave_params *params,
489 snd_config_t *bindings,
491 snd_config_t *root, snd_config_t *sconf,
492 snd_pcm_stream_t stream, int mode)
494 snd_pcm_t *pcm = NULL, *spcm = NULL;
495 snd_pcm_direct_t *dsnoop = NULL;
496 int ret, first_instance, fail_sem_loop = 10;
500 if (stream != SND_PCM_STREAM_CAPTURE) {
501 SNDERR("The dsnoop plugin supports only capture stream");
505 dsnoop = calloc(1, sizeof(snd_pcm_direct_t));
511 ret = snd_pcm_direct_parse_bindings(dsnoop, bindings);
515 dsnoop->ipc_key = ipc_key;
516 dsnoop->ipc_perm = ipc_perm;
517 dsnoop->ipc_gid = ipc_gid;
521 ret = snd_pcm_new(&pcm, dsnoop->type = SND_PCM_TYPE_DSNOOP, name, stream, mode);
526 ret = snd_pcm_direct_semaphore_create_or_connect(dsnoop);
528 SNDERR("unable to create IPC semaphore");
532 ret = snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
534 snd_pcm_direct_semaphore_discard(dsnoop);
535 if (--fail_sem_loop <= 0)
542 first_instance = ret = snd_pcm_direct_shm_create_or_connect(dsnoop);
544 SNDERR("unable to create IPC shm instance");
548 pcm->ops = &snd_pcm_dsnoop_ops;
549 pcm->fast_ops = &snd_pcm_dsnoop_fast_ops;
550 pcm->private_data = dsnoop;
551 dsnoop->state = SND_PCM_STATE_OPEN;
552 dsnoop->slowptr = slowptr;
553 dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr;
555 if (first_instance) {
556 /* recursion is already checked in
557 snd_pcm_direct_get_slave_ipc_offset() */
558 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
559 mode | SND_PCM_NONBLOCK, NULL);
561 SNDERR("unable to open slave");
565 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
566 SNDERR("dsnoop plugin can be only connected to hw plugin");
570 ret = snd_pcm_direct_initialize_slave(dsnoop, spcm, params);
572 SNDERR("unable to initialize slave");
578 ret = snd_pcm_direct_server_create(dsnoop);
580 SNDERR("unable to create server");
584 dsnoop->shmptr->type = spcm->type;
586 /* up semaphore to avoid deadlock */
587 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
588 ret = snd_pcm_direct_client_connect(dsnoop);
590 SNDERR("unable to connect client");
594 snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT);
596 ret = snd_pcm_direct_open_secondary_client(&spcm, dsnoop, "dsnoop_client");
602 ret = snd_pcm_direct_initialize_poll_fd(dsnoop);
604 SNDERR("unable to initialize poll_fd");
608 pcm->poll_fd = dsnoop->poll_fd;
609 pcm->poll_events = POLLIN; /* it's different than other plugins */
612 snd_pcm_set_hw_ptr(pcm, &dsnoop->hw_ptr, -1, 0);
613 snd_pcm_set_appl_ptr(pcm, &dsnoop->appl_ptr, -1, 0);
615 if (dsnoop->channels == UINT_MAX)
616 dsnoop->channels = dsnoop->shmptr->s.channels;
618 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
625 snd_timer_close(dsnoop->timer);
627 snd_pcm_direct_server_discard(dsnoop);
629 snd_pcm_direct_client_discard(dsnoop);
632 if (dsnoop->shmid >= 0)
633 snd_pcm_direct_shm_discard(dsnoop);
634 if (snd_pcm_direct_semaphore_discard(dsnoop) < 0)
635 snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT);
638 free(dsnoop->bindings);
646 /*! \page pcm_plugins
648 \section pcm_plugins_dsnoop Plugin: dsnoop
650 This plugin splits one capture stream to more.
651 It works the reverse way of \ref pcm_plugins_dmix "dmix plugin",
652 reading the shared capture buffer from many clients concurrently.
653 The meaning of parameters below are almost identical with
658 type dsnoop # Direct snoop
659 ipc_key INT # unique IPC key
660 ipc_key_add_uid BOOL # add current uid to unique IPC key
661 ipc_perm INT # IPC permissions (octal, default 0600)
664 slave { # Slave definition
665 pcm STR # slave PCM name
667 pcm { } # slave PCM definition
668 format STR # format definition
669 rate INT # rate definition
671 period_time INT # in usec
673 period_size INT # in bytes
674 buffer_time INT # in usec
676 buffer_size INT # in bytes
677 periods INT # when buffer_size or buffer_time is not specified
679 bindings { # note: this is client independent!!!
680 N INT # maps slave channel to client channel N
682 slowptr BOOL # slow but more precise pointer updates
686 \subsection pcm_plugins_dsnoop_funcref Function reference
689 <LI>snd_pcm_dsnoop_open()
690 <LI>_snd_pcm_dsnoop_open()
696 * \brief Creates a new dsnoop PCM
697 * \param pcmp Returns created PCM handle
698 * \param name Name of PCM
699 * \param root Root configuration node
700 * \param conf Configuration node with dsnoop PCM description
701 * \param stream PCM Stream
702 * \param mode PCM Mode
703 * \warning Using of this function might be dangerous in the sense
704 * of compatibility reasons. The prototype might be freely
707 int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name,
708 snd_config_t *root, snd_config_t *conf,
709 snd_pcm_stream_t stream, int mode)
712 struct slave_params params;
713 struct snd_pcm_direct_open_conf dopen;
718 err = snd_pcm_direct_parse_open_conf(conf, &dopen);
722 /* the default settings, it might be invalid for some hardware */
723 params.format = SND_PCM_FORMAT_S16;
726 params.period_time = -1;
727 params.buffer_time = -1;
730 err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
731 SND_PCM_HW_PARAM_FORMAT, 0, ¶ms.format,
732 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
733 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
734 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
735 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
736 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
737 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
738 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
742 /* set a reasonable default */
743 if (psize == -1 && params.period_time == -1)
744 params.period_time = 125000; /* 0.125 seconds */
746 params.period_size = psize;
747 params.buffer_size = bsize;
749 ipc_offset = snd_pcm_direct_get_slave_ipc_offset(root, sconf, stream);
750 if (ipc_offset < 0) {
751 snd_config_delete(sconf);
754 dopen.ipc_key += ipc_offset;
756 err = snd_pcm_dsnoop_open(pcmp, name, dopen.ipc_key, dopen.ipc_perm, dopen.ipc_gid,
757 ¶ms, dopen.bindings, dopen.slowptr,
758 root, sconf, stream, mode);
760 snd_config_delete(sconf);
764 SND_DLSYM_BUILD_VERSION(_snd_pcm_dsnoop_open, SND_PCM_DLSYM_VERSION);