2 * \file pcm/pcm_dshare.c
4 * \brief PCM Direct Sharing of Channels Plugin Interface
5 * \author Jaroslav Kysela <perex@suse.cz>
9 * PCM - Direct Sharing of Channels
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_dshare = "";
54 /* start is pending - this state happens when rate plugin does a delayed commit */
55 #define STATE_RUN_PENDING 1024
58 static void do_silence(snd_pcm_t *pcm)
60 snd_pcm_direct_t *dshare = pcm->private_data;
61 const snd_pcm_channel_area_t *dst_areas;
62 unsigned int chn, dchn, channels;
63 snd_pcm_format_t format;
65 dst_areas = snd_pcm_mmap_areas(dshare->spcm);
66 channels = dshare->channels;
67 format = dshare->shmptr->s.format;
68 for (chn = 0; chn < channels; chn++) {
69 dchn = dshare->bindings ? dshare->bindings[chn] : chn;
70 snd_pcm_area_silence(&dst_areas[dchn], 0, dshare->shmptr->s.buffer_size, format);
74 static void share_areas(snd_pcm_direct_t *dshare,
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, dchn, channels;
82 snd_pcm_format_t format;
84 channels = dshare->channels;
85 format = dshare->shmptr->s.format;
86 if (dshare->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 dchn = dshare->bindings ? dshare->bindings[chn] : chn;
94 snd_pcm_area_copy(&dst_areas[dchn], dst_ofs, &src_areas[chn], src_ofs, size, format);
101 * synchronize shm ring buffer with hardware
103 static void snd_pcm_dshare_sync_area(snd_pcm_t *pcm)
105 snd_pcm_direct_t *dshare = pcm->private_data;
106 snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size;
107 snd_pcm_uframes_t appl_ptr, size;
108 const snd_pcm_channel_area_t *src_areas, *dst_areas;
110 /* calculate the size to transfer */
111 size = dshare->appl_ptr - dshare->last_appl_ptr;
114 slave_hw_ptr = dshare->slave_hw_ptr;
115 /* don't write on the last active period - this area may be cleared
116 * by the driver during write operation...
118 slave_hw_ptr -= slave_hw_ptr % dshare->slave_period_size;
119 slave_hw_ptr += dshare->slave_buffer_size;
120 if (dshare->slave_hw_ptr > dshare->slave_boundary)
121 slave_hw_ptr -= dshare->slave_boundary;
122 if (slave_hw_ptr < dshare->slave_appl_ptr)
123 slave_size = slave_hw_ptr + (dshare->slave_boundary - dshare->slave_appl_ptr);
125 slave_size = slave_hw_ptr - dshare->slave_appl_ptr;
126 if (slave_size < size)
131 /* add sample areas here */
132 src_areas = snd_pcm_mmap_areas(pcm);
133 dst_areas = snd_pcm_mmap_areas(dshare->spcm);
134 appl_ptr = dshare->last_appl_ptr % pcm->buffer_size;
135 dshare->last_appl_ptr += size;
136 dshare->last_appl_ptr %= pcm->boundary;
137 slave_appl_ptr = dshare->slave_appl_ptr % dshare->slave_buffer_size;
138 dshare->slave_appl_ptr += size;
139 dshare->slave_appl_ptr %= dshare->slave_boundary;
141 snd_pcm_uframes_t transfer = size;
142 if (appl_ptr + transfer > pcm->buffer_size)
143 transfer = pcm->buffer_size - appl_ptr;
144 if (slave_appl_ptr + transfer > dshare->slave_buffer_size)
145 transfer = dshare->slave_buffer_size - slave_appl_ptr;
146 share_areas(dshare, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
150 slave_appl_ptr += transfer;
151 slave_appl_ptr %= dshare->slave_buffer_size;
152 appl_ptr += transfer;
153 appl_ptr %= pcm->buffer_size;
158 * synchronize hardware pointer (hw_ptr) with ours
160 static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm)
162 snd_pcm_direct_t *dshare = pcm->private_data;
163 snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail;
164 snd_pcm_sframes_t diff;
166 switch (snd_pcm_state(dshare->spcm)) {
167 case SND_PCM_STATE_DISCONNECTED:
168 dshare->state = SNDRV_PCM_STATE_DISCONNECTED;
174 snd_pcm_hwsync(dshare->spcm);
175 old_slave_hw_ptr = dshare->slave_hw_ptr;
176 slave_hw_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
177 diff = slave_hw_ptr - old_slave_hw_ptr;
178 if (diff == 0) /* fast path */
180 if (dshare->state != SND_PCM_STATE_RUNNING &&
181 dshare->state != SND_PCM_STATE_DRAINING)
182 /* not really started yet - don't update hw_ptr */
185 slave_hw_ptr += dshare->slave_boundary;
186 diff = slave_hw_ptr - old_slave_hw_ptr;
188 dshare->hw_ptr += diff;
189 dshare->hw_ptr %= pcm->boundary;
190 // printf("sync ptr diff = %li\n", diff);
191 if (pcm->stop_threshold >= pcm->boundary) /* don't care */
193 avail = snd_pcm_mmap_playback_avail(pcm);
194 if (avail > dshare->avail_max)
195 dshare->avail_max = avail;
196 if (avail >= pcm->stop_threshold) {
198 snd_timer_stop(dshare->timer);
199 gettimeofday(&tv, 0);
200 dshare->trigger_tstamp.tv_sec = tv.tv_sec;
201 dshare->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
202 if (dshare->state == SND_PCM_STATE_RUNNING) {
203 dshare->state = SND_PCM_STATE_XRUN;
206 dshare->state = SND_PCM_STATE_SETUP;
207 /* clear queue to remove pending poll events */
208 snd_pcm_direct_clear_timer_queue(dshare);
214 * plugin implementation
217 static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
219 snd_pcm_direct_t *dshare = pcm->private_data;
221 switch (dshare->state) {
222 case SNDRV_PCM_STATE_DRAINING:
223 case SNDRV_PCM_STATE_RUNNING:
224 snd_pcm_dshare_sync_ptr(pcm);
229 memset(status, 0, sizeof(*status));
230 status->state = snd_pcm_state(dshare->spcm);
231 status->trigger_tstamp = dshare->trigger_tstamp;
232 status->tstamp = snd_pcm_hw_fast_tstamp(dshare->spcm);
233 status->avail = snd_pcm_mmap_playback_avail(pcm);
234 status->avail_max = status->avail > dshare->avail_max ? status->avail : dshare->avail_max;
235 dshare->avail_max = 0;
239 static snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm)
241 snd_pcm_direct_t *dshare = pcm->private_data;
242 switch (snd_pcm_state(dshare->spcm)) {
243 case SND_PCM_STATE_SUSPENDED:
244 return SND_PCM_STATE_SUSPENDED;
245 case SND_PCM_STATE_DISCONNECTED:
246 return SND_PCM_STATE_DISCONNECTED;
250 if (dshare->state == STATE_RUN_PENDING)
251 return SNDRV_PCM_STATE_RUNNING;
252 return dshare->state;
255 static int snd_pcm_dshare_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
257 snd_pcm_direct_t *dshare = pcm->private_data;
260 switch (dshare->state) {
261 case SNDRV_PCM_STATE_DRAINING:
262 case SNDRV_PCM_STATE_RUNNING:
263 err = snd_pcm_dshare_sync_ptr(pcm);
267 case SNDRV_PCM_STATE_PREPARED:
268 case SNDRV_PCM_STATE_SUSPENDED:
269 case STATE_RUN_PENDING:
270 *delayp = snd_pcm_mmap_playback_hw_avail(pcm);
272 case SNDRV_PCM_STATE_XRUN:
274 case SNDRV_PCM_STATE_DISCONNECTED:
281 static int snd_pcm_dshare_hwsync(snd_pcm_t *pcm)
283 snd_pcm_direct_t *dshare = pcm->private_data;
285 switch(dshare->state) {
286 case SNDRV_PCM_STATE_DRAINING:
287 case SNDRV_PCM_STATE_RUNNING:
288 return snd_pcm_dshare_sync_ptr(pcm);
289 case SNDRV_PCM_STATE_PREPARED:
290 case SNDRV_PCM_STATE_SUSPENDED:
292 case SNDRV_PCM_STATE_XRUN:
294 case SNDRV_PCM_STATE_DISCONNECTED:
301 static int snd_pcm_dshare_prepare(snd_pcm_t *pcm)
303 snd_pcm_direct_t *dshare = pcm->private_data;
305 snd_pcm_direct_check_interleave(dshare, pcm);
306 dshare->state = SND_PCM_STATE_PREPARED;
307 dshare->appl_ptr = dshare->last_appl_ptr = 0;
309 return snd_pcm_direct_set_timer_params(dshare);
312 static int snd_pcm_dshare_reset(snd_pcm_t *pcm)
314 snd_pcm_direct_t *dshare = pcm->private_data;
315 dshare->hw_ptr %= pcm->period_size;
316 dshare->appl_ptr = dshare->last_appl_ptr = dshare->hw_ptr;
317 dshare->slave_appl_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
321 static int snd_pcm_dshare_start_timer(snd_pcm_direct_t *dshare)
325 snd_pcm_hwsync(dshare->spcm);
326 dshare->slave_appl_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
327 err = snd_timer_start(dshare->timer);
330 dshare->state = SND_PCM_STATE_RUNNING;
334 static int snd_pcm_dshare_start(snd_pcm_t *pcm)
336 snd_pcm_direct_t *dshare = pcm->private_data;
337 snd_pcm_sframes_t avail;
341 if (dshare->state != SND_PCM_STATE_PREPARED)
343 avail = snd_pcm_mmap_playback_hw_avail(pcm);
345 dshare->state = STATE_RUN_PENDING;
349 if ((err = snd_pcm_dshare_start_timer(dshare)) < 0)
351 snd_pcm_dshare_sync_area(pcm);
353 gettimeofday(&tv, 0);
354 dshare->trigger_tstamp.tv_sec = tv.tv_sec;
355 dshare->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
359 static int snd_pcm_dshare_drop(snd_pcm_t *pcm)
361 snd_pcm_direct_t *dshare = pcm->private_data;
362 if (dshare->state == SND_PCM_STATE_OPEN)
364 snd_pcm_direct_timer_stop(dshare);
366 dshare->state = SND_PCM_STATE_SETUP;
370 static int snd_pcm_dshare_drain(snd_pcm_t *pcm)
372 snd_pcm_direct_t *dshare = pcm->private_data;
373 snd_pcm_uframes_t stop_threshold;
376 if (dshare->state == SND_PCM_STATE_OPEN)
378 if (pcm->mode & SND_PCM_NONBLOCK)
380 if (dshare->state == SND_PCM_STATE_PREPARED) {
381 if (snd_pcm_mmap_playback_hw_avail(pcm) > 0)
382 snd_pcm_dshare_start(pcm);
384 snd_pcm_dshare_drop(pcm);
389 if (dshare->state == SND_PCM_STATE_XRUN) {
390 snd_pcm_dshare_drop(pcm);
394 stop_threshold = pcm->stop_threshold;
395 if (pcm->stop_threshold > pcm->buffer_size)
396 pcm->stop_threshold = pcm->buffer_size;
397 dshare->state = SND_PCM_STATE_DRAINING;
399 err = snd_pcm_dshare_sync_ptr(pcm);
401 snd_pcm_dshare_drop(pcm);
404 if (dshare->state == SND_PCM_STATE_DRAINING) {
405 snd_pcm_dshare_sync_area(pcm);
406 snd_pcm_wait_nocheck(pcm, -1);
407 snd_pcm_direct_clear_timer_queue(dshare); /* force poll to wait */
409 } while (dshare->state == SND_PCM_STATE_DRAINING);
410 pcm->stop_threshold = stop_threshold;
414 static int snd_pcm_dshare_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
419 static snd_pcm_sframes_t snd_pcm_dshare_rewind(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_uframes_t frames ATTRIBUTE_UNUSED)
422 /* FIXME: substract samples from the mix ring buffer, too? */
423 snd_pcm_mmap_appl_backward(pcm, frames);
430 static snd_pcm_sframes_t snd_pcm_dshare_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
432 snd_pcm_sframes_t avail;
434 avail = snd_pcm_mmap_playback_avail(pcm);
437 if (frames > (snd_pcm_uframes_t)avail)
439 snd_pcm_mmap_appl_forward(pcm, frames);
443 static snd_pcm_sframes_t snd_pcm_dshare_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
448 static snd_pcm_sframes_t snd_pcm_dshare_readn(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
453 static int snd_pcm_dshare_close(snd_pcm_t *pcm)
455 snd_pcm_direct_t *dshare = pcm->private_data;
458 snd_timer_close(dshare->timer);
460 snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT);
461 dshare->shmptr->u.dshare.chn_mask &= ~dshare->u.dshare.chn_mask;
462 snd_pcm_close(dshare->spcm);
464 snd_pcm_direct_server_discard(dshare);
466 snd_pcm_direct_client_discard(dshare);
467 snd_pcm_direct_shm_discard(dshare);
468 snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
469 free(dshare->bindings);
470 pcm->private_data = NULL;
475 static snd_pcm_sframes_t snd_pcm_dshare_mmap_commit(snd_pcm_t *pcm,
476 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
477 snd_pcm_uframes_t size)
479 snd_pcm_direct_t *dshare = pcm->private_data;
482 switch (snd_pcm_state(dshare->spcm)) {
483 case SND_PCM_STATE_XRUN:
485 case SND_PCM_STATE_SUSPENDED:
492 snd_pcm_mmap_appl_forward(pcm, size);
493 if (dshare->state == STATE_RUN_PENDING) {
494 if ((err = snd_pcm_dshare_start_timer(dshare)) < 0)
496 } else if (dshare->state == SND_PCM_STATE_RUNNING ||
497 dshare->state == SND_PCM_STATE_DRAINING)
498 snd_pcm_dshare_sync_ptr(pcm);
499 if (dshare->state == SND_PCM_STATE_RUNNING ||
500 dshare->state == SND_PCM_STATE_DRAINING) {
501 /* ok, we commit the changes after the validation of area */
502 /* it's intended, although the result might be crappy */
503 snd_pcm_dshare_sync_area(pcm);
504 /* clear timer queue to avoid a bogus return from poll */
505 if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
506 snd_pcm_direct_clear_timer_queue(dshare);
511 static snd_pcm_sframes_t snd_pcm_dshare_avail_update(snd_pcm_t *pcm)
513 snd_pcm_direct_t *dshare = pcm->private_data;
515 if (dshare->state == SND_PCM_STATE_RUNNING ||
516 dshare->state == SND_PCM_STATE_DRAINING)
517 snd_pcm_dshare_sync_ptr(pcm);
518 return snd_pcm_mmap_playback_avail(pcm);
521 static void snd_pcm_dshare_dump(snd_pcm_t *pcm, snd_output_t *out)
523 snd_pcm_direct_t *dshare = pcm->private_data;
525 snd_output_printf(out, "Direct Share PCM\n");
527 snd_output_printf(out, "Its setup is:\n");
528 snd_pcm_dump_setup(pcm, out);
531 snd_pcm_dump(dshare->spcm, out);
534 static snd_pcm_ops_t snd_pcm_dshare_ops = {
535 .close = snd_pcm_dshare_close,
536 .info = snd_pcm_direct_info,
537 .hw_refine = snd_pcm_direct_hw_refine,
538 .hw_params = snd_pcm_direct_hw_params,
539 .hw_free = snd_pcm_direct_hw_free,
540 .sw_params = snd_pcm_direct_sw_params,
541 .channel_info = snd_pcm_direct_channel_info,
542 .dump = snd_pcm_dshare_dump,
543 .nonblock = snd_pcm_direct_nonblock,
544 .async = snd_pcm_direct_async,
545 .mmap = snd_pcm_direct_mmap,
546 .munmap = snd_pcm_direct_munmap,
549 static snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = {
550 .status = snd_pcm_dshare_status,
551 .state = snd_pcm_dshare_state,
552 .hwsync = snd_pcm_dshare_hwsync,
553 .delay = snd_pcm_dshare_delay,
554 .prepare = snd_pcm_dshare_prepare,
555 .reset = snd_pcm_dshare_reset,
556 .start = snd_pcm_dshare_start,
557 .drop = snd_pcm_dshare_drop,
558 .drain = snd_pcm_dshare_drain,
559 .pause = snd_pcm_dshare_pause,
560 .rewind = snd_pcm_dshare_rewind,
561 .forward = snd_pcm_dshare_forward,
562 .resume = snd_pcm_direct_resume,
566 .writei = snd_pcm_mmap_writei,
567 .writen = snd_pcm_mmap_writen,
568 .readi = snd_pcm_dshare_readi,
569 .readn = snd_pcm_dshare_readn,
570 .avail_update = snd_pcm_dshare_avail_update,
571 .mmap_commit = snd_pcm_dshare_mmap_commit,
572 .poll_descriptors = NULL,
573 .poll_descriptors_count = NULL,
574 .poll_revents = snd_pcm_direct_poll_revents,
578 * \brief Creates a new dshare PCM
579 * \param pcmp Returns created PCM handle
580 * \param name Name of PCM
581 * \param ipc_key IPC key for semaphore and shared memory
582 * \param ipc_perm IPC permissions for semaphore and shared memory
583 * \param ipc_gid IPC group ID for semaphore and shared memory
584 * \param params Parameters for slave
585 * \param bindings Channel bindings
586 * \param slowptr Slow but more precise pointer updates
587 * \param root Configuration root
588 * \param sconf Slave configuration
589 * \param stream PCM Direction (stream)
590 * \param mode PCM Mode
591 * \retval zero on success otherwise a negative error code
592 * \warning Using of this function might be dangerous in the sense
593 * of compatibility reasons. The prototype might be freely
596 int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
597 key_t ipc_key, mode_t ipc_perm, int ipc_gid,
598 struct slave_params *params,
599 snd_config_t *bindings,
601 snd_config_t *root, snd_config_t *sconf,
602 snd_pcm_stream_t stream, int mode)
604 snd_pcm_t *pcm = NULL, *spcm = NULL;
605 snd_pcm_direct_t *dshare = NULL;
606 int ret, first_instance;
608 int fail_sem_loop = 10;
612 if (stream != SND_PCM_STREAM_PLAYBACK) {
613 SNDERR("The dshare plugin supports only playback stream");
617 dshare = calloc(1, sizeof(snd_pcm_direct_t));
623 ret = snd_pcm_direct_parse_bindings(dshare, bindings);
627 if (!dshare->bindings) {
628 SNDERR("dshare: specify bindings!!!");
633 dshare->ipc_key = ipc_key;
634 dshare->ipc_perm = ipc_perm;
635 dshare->ipc_gid = ipc_gid;
639 ret = snd_pcm_new(&pcm, dshare->type = SND_PCM_TYPE_DSHARE, name, stream, mode);
644 ret = snd_pcm_direct_semaphore_create_or_connect(dshare);
646 SNDERR("unable to create IPC semaphore");
650 ret = snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT);
652 snd_pcm_direct_semaphore_discard(dshare);
653 if (--fail_sem_loop <= 0)
660 first_instance = ret = snd_pcm_direct_shm_create_or_connect(dshare);
662 SNDERR("unable to create IPC shm instance");
666 pcm->ops = &snd_pcm_dshare_ops;
667 pcm->fast_ops = &snd_pcm_dshare_fast_ops;
668 pcm->private_data = dshare;
669 dshare->state = SND_PCM_STATE_OPEN;
670 dshare->slowptr = slowptr;
671 dshare->sync_ptr = snd_pcm_dshare_sync_ptr;
673 if (first_instance) {
674 /* recursion is already checked in
675 snd_pcm_direct_get_slave_ipc_offset() */
676 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
677 mode | SND_PCM_NONBLOCK, NULL);
679 SNDERR("unable to open slave");
683 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
684 SNDERR("dshare plugin can be only connected to hw plugin");
688 ret = snd_pcm_direct_initialize_slave(dshare, spcm, params);
690 SNDERR("unable to initialize slave");
696 ret = snd_pcm_direct_server_create(dshare);
698 SNDERR("unable to create server");
702 dshare->shmptr->type = spcm->type;
704 /* up semaphore to avoid deadlock */
705 snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
706 ret = snd_pcm_direct_client_connect(dshare);
708 SNDERR("unable to connect client");
712 snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT);
713 ret = snd_pcm_direct_open_secondary_client(&spcm, dshare, "dshare_client");
714 ret = snd_pcm_hw_open_fd(&spcm, "dshare_client", dshare->hw_fd, 0, 0);
720 for (chn = 0; chn < dshare->channels; chn++)
721 dshare->u.dshare.chn_mask |= (1ULL<<dshare->bindings[chn]);
722 if (dshare->shmptr->u.dshare.chn_mask & dshare->u.dshare.chn_mask) {
723 SNDERR("destination channel specified in bindings is already used");
724 dshare->u.dshare.chn_mask = 0;
728 dshare->shmptr->u.dshare.chn_mask |= dshare->u.dshare.chn_mask;
730 ret = snd_pcm_direct_initialize_poll_fd(dshare);
732 SNDERR("unable to initialize poll_fd");
736 pcm->poll_fd = dshare->poll_fd;
737 pcm->poll_events = POLLIN; /* it's different than other plugins */
740 snd_pcm_set_hw_ptr(pcm, &dshare->hw_ptr, -1, 0);
741 snd_pcm_set_appl_ptr(pcm, &dshare->appl_ptr, -1, 0);
743 snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
750 dshare->shmptr->u.dshare.chn_mask &= ~dshare->u.dshare.chn_mask;
752 snd_timer_close(dshare->timer);
754 snd_pcm_direct_server_discard(dshare);
756 snd_pcm_direct_client_discard(dshare);
759 if (dshare->shmid >= 0)
760 snd_pcm_direct_shm_discard(dshare);
761 if (snd_pcm_direct_semaphore_discard(dshare) < 0)
762 snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
765 free(dshare->bindings);
773 /*! \page pcm_plugins
775 \section pcm_plugins_dshare Plugin: dshare
777 This plugin provides sharing channels.
778 Unlike \ref pcm_plugins_share "share plugin", this plugin doesn't need
779 the explicit server program but accesses the shared buffer concurrently
780 from each client as well as \ref pcm_plugins_dmix "dmix" and
781 \ref pcm_plugins_dsnoop "dsnoop" plugins do.
782 The parameters below are almost identical with these plugins.
786 type dshare # Direct sharing
787 ipc_key INT # unique IPC key
788 ipc_key_add_uid BOOL # add current uid to unique IPC key
789 ipc_perm INT # IPC permissions (octal, default 0600)
792 slave { # Slave definition
793 pcm STR # slave PCM name
795 pcm { } # slave PCM definition
796 format STR # format definition
797 rate INT # rate definition
799 period_time INT # in usec
801 period_size INT # in bytes
802 buffer_time INT # in usec
804 buffer_size INT # in bytes
805 periods INT # when buffer_size or buffer_time is not specified
807 bindings { # note: this is client independent!!!
808 N INT # maps slave channel to client channel N
810 slowptr BOOL # slow but more precise pointer updates
814 \subsection pcm_plugins_dshare_funcref Function reference
817 <LI>snd_pcm_dshare_open()
818 <LI>_snd_pcm_dshare_open()
824 * \brief Creates a new dshare PCM
825 * \param pcmp Returns created PCM handle
826 * \param name Name of PCM
827 * \param root Root configuration node
828 * \param conf Configuration node with dshare PCM description
829 * \param stream PCM Stream
830 * \param mode PCM Mode
831 * \warning Using of this function might be dangerous in the sense
832 * of compatibility reasons. The prototype might be freely
835 int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
836 snd_config_t *root, snd_config_t *conf,
837 snd_pcm_stream_t stream, int mode)
840 struct slave_params params;
841 struct snd_pcm_direct_open_conf dopen;
846 err = snd_pcm_direct_parse_open_conf(conf, &dopen);
850 /* the default settings, it might be invalid for some hardware */
851 params.format = SND_PCM_FORMAT_S16;
854 params.period_time = -1;
855 params.buffer_time = -1;
858 err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
859 SND_PCM_HW_PARAM_FORMAT, 0, ¶ms.format,
860 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
861 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
862 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
863 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
864 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
865 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
866 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
870 /* set a reasonable default */
871 if (psize == -1 && params.period_time == -1)
872 params.period_time = 125000; /* 0.125 seconds */
874 params.period_size = psize;
875 params.buffer_size = bsize;
877 ipc_offset = snd_pcm_direct_get_slave_ipc_offset(root, sconf, stream);
878 if (ipc_offset < 0) {
879 snd_config_delete(sconf);
882 dopen.ipc_key += ipc_offset;
884 err = snd_pcm_dshare_open(pcmp, name, dopen.ipc_key, dopen.ipc_perm, dopen.ipc_gid,
885 ¶ms, dopen.bindings, dopen.slowptr,
886 root, sconf, stream, mode);
888 snd_config_delete(sconf);
892 SND_DLSYM_BUILD_VERSION(_snd_pcm_dshare_open, SND_PCM_DLSYM_VERSION);