2 * \file pcm/pcm_dshare.c
4 * \brief PCM Direct Sharing of Channels Plugin Interface
5 * \author Jaroslav Kysela <perex@perex.cz>
9 * PCM - Direct Sharing of Channels
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_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;
71 snd_pcm_area_silence(&dst_areas[dchn], 0,
72 dshare->shmptr->s.buffer_size, format);
76 static void share_areas(snd_pcm_direct_t *dshare,
77 const snd_pcm_channel_area_t *src_areas,
78 const snd_pcm_channel_area_t *dst_areas,
79 snd_pcm_uframes_t src_ofs,
80 snd_pcm_uframes_t dst_ofs,
81 snd_pcm_uframes_t size)
83 unsigned int chn, dchn, channels;
84 snd_pcm_format_t format;
86 channels = dshare->channels;
87 format = dshare->shmptr->s.format;
88 if (dshare->interleaved) {
89 unsigned int fbytes = snd_pcm_format_physical_width(format) / 8;
90 memcpy(((char *)dst_areas[0].addr) + (dst_ofs * channels * fbytes),
91 ((char *)src_areas[0].addr) + (src_ofs * channels * fbytes),
92 size * channels * fbytes);
94 for (chn = 0; chn < channels; chn++) {
95 dchn = dshare->bindings ? dshare->bindings[chn] : chn;
97 snd_pcm_area_copy(&dst_areas[dchn], dst_ofs,
98 &src_areas[chn], src_ofs, size, format);
105 * synchronize shm ring buffer with hardware
107 static void snd_pcm_dshare_sync_area(snd_pcm_t *pcm)
109 snd_pcm_direct_t *dshare = pcm->private_data;
110 snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size;
111 snd_pcm_uframes_t appl_ptr, size;
112 const snd_pcm_channel_area_t *src_areas, *dst_areas;
114 /* calculate the size to transfer */
115 size = dshare->appl_ptr - dshare->last_appl_ptr;
118 slave_hw_ptr = dshare->slave_hw_ptr;
119 /* don't write on the last active period - this area may be cleared
120 * by the driver during write operation...
122 slave_hw_ptr -= slave_hw_ptr % dshare->slave_period_size;
123 slave_hw_ptr += dshare->slave_buffer_size;
124 if (slave_hw_ptr >= dshare->slave_boundary)
125 slave_hw_ptr -= dshare->slave_boundary;
126 if (slave_hw_ptr < dshare->slave_appl_ptr)
127 slave_size = slave_hw_ptr + (dshare->slave_boundary - dshare->slave_appl_ptr);
129 slave_size = slave_hw_ptr - dshare->slave_appl_ptr;
130 if (slave_size < size)
135 /* add sample areas here */
136 src_areas = snd_pcm_mmap_areas(pcm);
137 dst_areas = snd_pcm_mmap_areas(dshare->spcm);
138 appl_ptr = dshare->last_appl_ptr % pcm->buffer_size;
139 dshare->last_appl_ptr += size;
140 dshare->last_appl_ptr %= pcm->boundary;
141 slave_appl_ptr = dshare->slave_appl_ptr % dshare->slave_buffer_size;
142 dshare->slave_appl_ptr += size;
143 dshare->slave_appl_ptr %= dshare->slave_boundary;
145 snd_pcm_uframes_t transfer = size;
146 if (appl_ptr + transfer > pcm->buffer_size)
147 transfer = pcm->buffer_size - appl_ptr;
148 if (slave_appl_ptr + transfer > dshare->slave_buffer_size)
149 transfer = dshare->slave_buffer_size - slave_appl_ptr;
150 share_areas(dshare, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
154 slave_appl_ptr += transfer;
155 slave_appl_ptr %= dshare->slave_buffer_size;
156 appl_ptr += transfer;
157 appl_ptr %= pcm->buffer_size;
162 * synchronize hardware pointer (hw_ptr) with ours
164 static int snd_pcm_dshare_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr)
166 snd_pcm_direct_t *dshare = pcm->private_data;
167 snd_pcm_uframes_t old_slave_hw_ptr, avail;
168 snd_pcm_sframes_t diff;
170 old_slave_hw_ptr = dshare->slave_hw_ptr;
171 dshare->slave_hw_ptr = slave_hw_ptr;
172 diff = slave_hw_ptr - old_slave_hw_ptr;
173 if (diff == 0) /* fast path */
175 if (dshare->state != SND_PCM_STATE_RUNNING &&
176 dshare->state != SND_PCM_STATE_DRAINING)
177 /* not really started yet - don't update hw_ptr */
180 slave_hw_ptr += dshare->slave_boundary;
181 diff = slave_hw_ptr - old_slave_hw_ptr;
183 dshare->hw_ptr += diff;
184 dshare->hw_ptr %= pcm->boundary;
185 // printf("sync ptr diff = %li\n", diff);
186 if (pcm->stop_threshold >= pcm->boundary) /* don't care */
188 avail = snd_pcm_mmap_playback_avail(pcm);
189 if (avail > dshare->avail_max)
190 dshare->avail_max = avail;
191 if (avail >= pcm->stop_threshold) {
192 snd_timer_stop(dshare->timer);
194 gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type);
195 if (dshare->state == SND_PCM_STATE_RUNNING) {
196 dshare->state = SND_PCM_STATE_XRUN;
199 dshare->state = SND_PCM_STATE_SETUP;
200 /* clear queue to remove pending poll events */
201 snd_pcm_direct_clear_timer_queue(dshare);
206 static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm)
208 snd_pcm_direct_t *dshare = pcm->private_data;
211 switch (snd_pcm_state(dshare->spcm)) {
212 case SND_PCM_STATE_DISCONNECTED:
213 dshare->state = SNDRV_PCM_STATE_DISCONNECTED;
215 case SND_PCM_STATE_XRUN:
216 if ((err = snd_pcm_direct_slave_recover(dshare)) < 0)
222 if (snd_pcm_direct_client_chk_xrun(dshare, pcm))
225 snd_pcm_hwsync(dshare->spcm);
227 return snd_pcm_dshare_sync_ptr0(pcm, *dshare->spcm->hw.ptr);
231 * plugin implementation
234 static snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm);
236 static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
238 snd_pcm_direct_t *dshare = pcm->private_data;
240 memset(status, 0, sizeof(*status));
241 snd_pcm_status(dshare->spcm, status);
243 switch (dshare->state) {
244 case SNDRV_PCM_STATE_DRAINING:
245 case SNDRV_PCM_STATE_RUNNING:
246 snd_pcm_dshare_sync_ptr0(pcm, status->hw_ptr);
247 status->delay += snd_pcm_mmap_playback_delay(pcm)
248 + status->avail - dshare->spcm->buffer_size;
253 status->state = snd_pcm_dshare_state(pcm);
254 status->trigger_tstamp = dshare->trigger_tstamp;
255 status->avail = snd_pcm_mmap_playback_avail(pcm);
256 status->avail_max = status->avail > dshare->avail_max ? status->avail : dshare->avail_max;
257 dshare->avail_max = 0;
261 static snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm)
263 snd_pcm_direct_t *dshare = pcm->private_data;
265 snd_pcm_state_t state;
266 state = snd_pcm_state(dshare->spcm);
268 case SND_PCM_STATE_SUSPENDED:
269 case SND_PCM_STATE_DISCONNECTED:
270 dshare->state = state;
272 case SND_PCM_STATE_XRUN:
273 if ((err = snd_pcm_direct_slave_recover(dshare)) < 0)
279 snd_pcm_direct_client_chk_xrun(dshare, pcm);
280 if (dshare->state == STATE_RUN_PENDING)
281 return SNDRV_PCM_STATE_RUNNING;
282 return dshare->state;
285 static int snd_pcm_dshare_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
287 snd_pcm_direct_t *dshare = pcm->private_data;
290 switch (dshare->state) {
291 case SNDRV_PCM_STATE_DRAINING:
292 case SNDRV_PCM_STATE_RUNNING:
293 err = snd_pcm_dshare_sync_ptr(pcm);
297 case SNDRV_PCM_STATE_PREPARED:
298 case SNDRV_PCM_STATE_SUSPENDED:
299 case STATE_RUN_PENDING:
300 *delayp = snd_pcm_mmap_playback_hw_avail(pcm);
302 case SNDRV_PCM_STATE_XRUN:
304 case SNDRV_PCM_STATE_DISCONNECTED:
311 static int snd_pcm_dshare_hwsync(snd_pcm_t *pcm)
313 snd_pcm_direct_t *dshare = pcm->private_data;
315 switch(dshare->state) {
316 case SNDRV_PCM_STATE_DRAINING:
317 case SNDRV_PCM_STATE_RUNNING:
318 return snd_pcm_dshare_sync_ptr(pcm);
319 case SNDRV_PCM_STATE_PREPARED:
320 case SNDRV_PCM_STATE_SUSPENDED:
322 case SNDRV_PCM_STATE_XRUN:
324 case SNDRV_PCM_STATE_DISCONNECTED:
331 static int snd_pcm_dshare_reset(snd_pcm_t *pcm)
333 snd_pcm_direct_t *dshare = pcm->private_data;
334 dshare->hw_ptr %= pcm->period_size;
335 dshare->appl_ptr = dshare->last_appl_ptr = dshare->hw_ptr;
336 dshare->slave_appl_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
337 snd_pcm_direct_reset_slave_ptr(pcm, dshare);
341 static int snd_pcm_dshare_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dshare)
345 snd_pcm_hwsync(dshare->spcm);
346 dshare->slave_appl_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
347 snd_pcm_direct_reset_slave_ptr(pcm, dshare);
348 err = snd_timer_start(dshare->timer);
351 dshare->state = SND_PCM_STATE_RUNNING;
355 static int snd_pcm_dshare_start(snd_pcm_t *pcm)
357 snd_pcm_direct_t *dshare = pcm->private_data;
358 snd_pcm_sframes_t avail;
361 if (dshare->state != SND_PCM_STATE_PREPARED)
363 avail = snd_pcm_mmap_playback_hw_avail(pcm);
365 dshare->state = STATE_RUN_PENDING;
369 err = snd_pcm_dshare_start_timer(pcm, dshare);
372 snd_pcm_dshare_sync_area(pcm);
374 gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type);
378 static int snd_pcm_dshare_drop(snd_pcm_t *pcm)
380 snd_pcm_direct_t *dshare = pcm->private_data;
381 if (dshare->state == SND_PCM_STATE_OPEN)
383 dshare->state = SND_PCM_STATE_SETUP;
384 snd_pcm_direct_timer_stop(dshare);
390 static int __snd_pcm_dshare_drain(snd_pcm_t *pcm)
392 snd_pcm_direct_t *dshare = pcm->private_data;
393 snd_pcm_uframes_t stop_threshold;
396 switch (snd_pcm_state(dshare->spcm)) {
397 case SND_PCM_STATE_SUSPENDED:
403 if (dshare->state == SND_PCM_STATE_OPEN)
405 if (pcm->mode & SND_PCM_NONBLOCK)
407 if (dshare->state == SND_PCM_STATE_PREPARED) {
408 if (snd_pcm_mmap_playback_hw_avail(pcm) > 0)
409 snd_pcm_dshare_start(pcm);
411 snd_pcm_dshare_drop(pcm);
416 if (dshare->state == SND_PCM_STATE_XRUN) {
417 snd_pcm_dshare_drop(pcm);
421 stop_threshold = pcm->stop_threshold;
422 if (pcm->stop_threshold > pcm->buffer_size)
423 pcm->stop_threshold = pcm->buffer_size;
424 dshare->state = SND_PCM_STATE_DRAINING;
426 err = snd_pcm_dshare_sync_ptr(pcm);
428 snd_pcm_dshare_drop(pcm);
431 if (dshare->state == SND_PCM_STATE_DRAINING) {
432 snd_pcm_dshare_sync_area(pcm);
433 snd_pcm_wait_nocheck(pcm, -1);
434 snd_pcm_direct_clear_timer_queue(dshare); /* force poll to wait */
436 switch (snd_pcm_state(dshare->spcm)) {
437 case SND_PCM_STATE_SUSPENDED:
443 } while (dshare->state == SND_PCM_STATE_DRAINING);
444 pcm->stop_threshold = stop_threshold;
448 static int snd_pcm_dshare_drain(snd_pcm_t *pcm)
453 err = __snd_pcm_dshare_drain(pcm);
458 static int snd_pcm_dshare_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
463 static snd_pcm_sframes_t snd_pcm_dshare_rewindable(snd_pcm_t *pcm)
465 return snd_pcm_mmap_playback_hw_rewindable(pcm);
468 static snd_pcm_sframes_t snd_pcm_dshare_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
470 snd_pcm_sframes_t avail;
472 avail = snd_pcm_dshare_rewindable(pcm);
473 if (frames > (snd_pcm_uframes_t)avail)
475 snd_pcm_mmap_appl_backward(pcm, frames);
479 static snd_pcm_sframes_t snd_pcm_dshare_forwardable(snd_pcm_t *pcm)
481 return snd_pcm_mmap_playback_avail(pcm);
484 static snd_pcm_sframes_t snd_pcm_dshare_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
486 snd_pcm_sframes_t avail;
488 avail = snd_pcm_dshare_forwardable(pcm);
489 if (frames > (snd_pcm_uframes_t)avail)
491 snd_pcm_mmap_appl_forward(pcm, frames);
495 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)
500 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)
505 static int snd_pcm_dshare_close(snd_pcm_t *pcm)
507 snd_pcm_direct_t *dshare = pcm->private_data;
510 snd_timer_close(dshare->timer);
512 snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT);
513 dshare->shmptr->u.dshare.chn_mask &= ~dshare->u.dshare.chn_mask;
514 snd_pcm_close(dshare->spcm);
516 snd_pcm_direct_server_discard(dshare);
518 snd_pcm_direct_client_discard(dshare);
519 if (snd_pcm_direct_shm_discard(dshare)) {
520 if (snd_pcm_direct_semaphore_discard(dshare))
521 snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT);
523 snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT);
524 free(dshare->bindings);
525 pcm->private_data = NULL;
530 static snd_pcm_sframes_t snd_pcm_dshare_mmap_commit(snd_pcm_t *pcm,
531 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
532 snd_pcm_uframes_t size)
534 snd_pcm_direct_t *dshare = pcm->private_data;
537 switch (snd_pcm_state(dshare->spcm)) {
538 case SND_PCM_STATE_XRUN:
539 if ((err = snd_pcm_direct_slave_recover(dshare)) < 0)
542 case SND_PCM_STATE_SUSPENDED:
547 if (snd_pcm_direct_client_chk_xrun(dshare, pcm))
551 snd_pcm_mmap_appl_forward(pcm, size);
552 if (dshare->state == STATE_RUN_PENDING) {
553 err = snd_pcm_dshare_start_timer(pcm, dshare);
556 } else if (dshare->state == SND_PCM_STATE_RUNNING ||
557 dshare->state == SND_PCM_STATE_DRAINING) {
558 if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0)
561 if (dshare->state == SND_PCM_STATE_RUNNING ||
562 dshare->state == SND_PCM_STATE_DRAINING) {
563 /* ok, we commit the changes after the validation of area */
564 /* it's intended, although the result might be crappy */
565 snd_pcm_dshare_sync_area(pcm);
566 /* clear timer queue to avoid a bogus return from poll */
567 if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
568 snd_pcm_direct_clear_timer_queue(dshare);
573 static snd_pcm_sframes_t snd_pcm_dshare_avail_update(snd_pcm_t *pcm)
575 snd_pcm_direct_t *dshare = pcm->private_data;
578 if (dshare->state == SND_PCM_STATE_RUNNING ||
579 dshare->state == SND_PCM_STATE_DRAINING) {
580 if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0)
583 if (dshare->state == SND_PCM_STATE_XRUN)
586 return snd_pcm_mmap_playback_avail(pcm);
589 static int snd_pcm_dshare_htimestamp(snd_pcm_t *pcm,
590 snd_pcm_uframes_t *avail,
591 snd_htimestamp_t *tstamp)
593 snd_pcm_direct_t *dshare = pcm->private_data;
594 snd_pcm_uframes_t avail1;
598 if (dshare->state == SND_PCM_STATE_RUNNING ||
599 dshare->state == SND_PCM_STATE_DRAINING)
600 snd_pcm_dshare_sync_ptr(pcm);
601 avail1 = snd_pcm_mmap_playback_avail(pcm);
602 if (ok && *avail == avail1)
605 *tstamp = snd_pcm_hw_fast_tstamp(dshare->spcm);
611 static void snd_pcm_dshare_dump(snd_pcm_t *pcm, snd_output_t *out)
613 snd_pcm_direct_t *dshare = pcm->private_data;
615 snd_output_printf(out, "Direct Share PCM\n");
617 snd_output_printf(out, "Its setup is:\n");
618 snd_pcm_dump_setup(pcm, out);
621 snd_pcm_dump(dshare->spcm, out);
624 static const snd_pcm_ops_t snd_pcm_dshare_ops = {
625 .close = snd_pcm_dshare_close,
626 .info = snd_pcm_direct_info,
627 .hw_refine = snd_pcm_direct_hw_refine,
628 .hw_params = snd_pcm_direct_hw_params,
629 .hw_free = snd_pcm_direct_hw_free,
630 .sw_params = snd_pcm_direct_sw_params,
631 .channel_info = snd_pcm_direct_channel_info,
632 .dump = snd_pcm_dshare_dump,
633 .nonblock = snd_pcm_direct_nonblock,
634 .async = snd_pcm_direct_async,
635 .mmap = snd_pcm_direct_mmap,
636 .munmap = snd_pcm_direct_munmap,
637 .get_chmap = snd_pcm_direct_get_chmap,
638 .set_chmap = snd_pcm_direct_set_chmap,
641 static const snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = {
642 .status = snd_pcm_dshare_status,
643 .state = snd_pcm_dshare_state,
644 .hwsync = snd_pcm_dshare_hwsync,
645 .delay = snd_pcm_dshare_delay,
646 .prepare = snd_pcm_direct_prepare,
647 .reset = snd_pcm_dshare_reset,
648 .start = snd_pcm_dshare_start,
649 .drop = snd_pcm_dshare_drop,
650 .drain = snd_pcm_dshare_drain,
651 .pause = snd_pcm_dshare_pause,
652 .rewindable = snd_pcm_dshare_rewindable,
653 .rewind = snd_pcm_dshare_rewind,
654 .forwardable = snd_pcm_dshare_forwardable,
655 .forward = snd_pcm_dshare_forward,
656 .resume = snd_pcm_direct_resume,
660 .writei = snd_pcm_mmap_writei,
661 .writen = snd_pcm_mmap_writen,
662 .readi = snd_pcm_dshare_readi,
663 .readn = snd_pcm_dshare_readn,
664 .avail_update = snd_pcm_dshare_avail_update,
665 .mmap_commit = snd_pcm_dshare_mmap_commit,
666 .htimestamp = snd_pcm_dshare_htimestamp,
667 .poll_descriptors = snd_pcm_direct_poll_descriptors,
668 .poll_descriptors_count = NULL,
669 .poll_revents = snd_pcm_direct_poll_revents,
673 * \brief Creates a new dshare PCM
674 * \param pcmp Returns created PCM handle
675 * \param name Name of PCM
676 * \param opts Direct PCM configurations
677 * \param params Parameters for slave
678 * \param root Configuration root
679 * \param sconf Slave configuration
680 * \param stream PCM Direction (stream)
681 * \param mode PCM Mode
682 * \retval zero on success otherwise a negative error code
683 * \warning Using of this function might be dangerous in the sense
684 * of compatibility reasons. The prototype might be freely
687 int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
688 struct snd_pcm_direct_open_conf *opts,
689 struct slave_params *params,
690 snd_config_t *root, snd_config_t *sconf,
691 snd_pcm_stream_t stream, int mode)
693 snd_pcm_t *pcm = NULL, *spcm = NULL;
694 snd_pcm_direct_t *dshare = NULL;
695 int ret, first_instance;
697 int fail_sem_loop = 10;
701 if (stream != SND_PCM_STREAM_PLAYBACK) {
702 SNDERR("The dshare plugin supports only playback stream");
706 dshare = calloc(1, sizeof(snd_pcm_direct_t));
712 ret = snd_pcm_direct_parse_bindings(dshare, params, opts->bindings);
716 if (!dshare->bindings) {
717 SNDERR("dshare: specify bindings!!!");
722 dshare->ipc_key = opts->ipc_key;
723 dshare->ipc_perm = opts->ipc_perm;
724 dshare->ipc_gid = opts->ipc_gid;
728 ret = snd_pcm_new(&pcm, dshare->type = SND_PCM_TYPE_DSHARE, name, stream, mode);
733 ret = snd_pcm_direct_semaphore_create_or_connect(dshare);
735 SNDERR("unable to create IPC semaphore");
739 ret = snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT);
741 snd_pcm_direct_semaphore_discard(dshare);
742 if (--fail_sem_loop <= 0)
749 first_instance = ret = snd_pcm_direct_shm_create_or_connect(dshare);
751 SNDERR("unable to create IPC shm instance");
755 pcm->ops = &snd_pcm_dshare_ops;
756 pcm->fast_ops = &snd_pcm_dshare_fast_ops;
757 pcm->private_data = dshare;
758 dshare->state = SND_PCM_STATE_OPEN;
759 dshare->slowptr = opts->slowptr;
760 dshare->max_periods = opts->max_periods;
761 dshare->var_periodsize = opts->var_periodsize;
762 dshare->hw_ptr_alignment = opts->hw_ptr_alignment;
763 dshare->sync_ptr = snd_pcm_dshare_sync_ptr;
766 if (first_instance) {
767 /* recursion is already checked in
768 snd_pcm_direct_get_slave_ipc_offset() */
769 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
770 mode | SND_PCM_NONBLOCK, NULL);
772 SNDERR("unable to open slave");
776 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
777 SNDERR("dshare plugin can be only connected to hw plugin");
781 ret = snd_pcm_direct_initialize_slave(dshare, spcm, params);
783 SNDERR("unable to initialize slave");
789 if (dshare->shmptr->use_server) {
790 ret = snd_pcm_direct_server_create(dshare);
792 SNDERR("unable to create server");
797 dshare->shmptr->type = spcm->type;
799 if (dshare->shmptr->use_server) {
800 /* up semaphore to avoid deadlock */
801 snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
802 ret = snd_pcm_direct_client_connect(dshare);
804 SNDERR("unable to connect client");
808 snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT);
809 ret = snd_pcm_direct_open_secondary_client(&spcm, dshare, "dshare_client");
815 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
816 mode | SND_PCM_NONBLOCK |
820 /* all other streams have been closed;
821 * retry as the first instance
823 if (ret == -EBADFD) {
827 SNDERR("unable to open slave");
830 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
831 SNDERR("dshare plugin can be only connected to hw plugin");
836 ret = snd_pcm_direct_initialize_secondary_slave(dshare, spcm, params);
838 SNDERR("unable to initialize slave");
846 for (chn = 0; chn < dshare->channels; chn++) {
847 unsigned int dchn = dshare->bindings ? dshare->bindings[chn] : chn;
848 if (dchn != UINT_MAX)
849 dshare->u.dshare.chn_mask |= (1ULL << dchn);
851 if (dshare->shmptr->u.dshare.chn_mask & dshare->u.dshare.chn_mask) {
852 SNDERR("destination channel specified in bindings is already used");
853 dshare->u.dshare.chn_mask = 0;
857 dshare->shmptr->u.dshare.chn_mask |= dshare->u.dshare.chn_mask;
859 ret = snd_pcm_direct_initialize_poll_fd(dshare);
861 SNDERR("unable to initialize poll_fd");
865 pcm->poll_fd = dshare->poll_fd;
866 pcm->poll_events = POLLIN; /* it's different than other plugins */
867 pcm->tstamp_type = spcm->tstamp_type;
869 snd_pcm_set_hw_ptr(pcm, &dshare->hw_ptr, -1, 0);
870 snd_pcm_set_appl_ptr(pcm, &dshare->appl_ptr, -1, 0);
872 snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
879 dshare->shmptr->u.dshare.chn_mask &= ~dshare->u.dshare.chn_mask;
881 snd_timer_close(dshare->timer);
883 snd_pcm_direct_server_discard(dshare);
885 snd_pcm_direct_client_discard(dshare);
888 if ((dshare->shmid >= 0) && (snd_pcm_direct_shm_discard(dshare))) {
889 if (snd_pcm_direct_semaphore_discard(dshare))
890 snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT);
892 snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT);
895 free(dshare->bindings);
903 /*! \page pcm_plugins
905 \section pcm_plugins_dshare Plugin: dshare
907 This plugin provides sharing channels.
908 Unlike \ref pcm_plugins_share "share plugin", this plugin doesn't need
909 the explicit server program but accesses the shared buffer concurrently
910 from each client as well as \ref pcm_plugins_dmix "dmix" and
911 \ref pcm_plugins_dsnoop "dsnoop" plugins do.
912 The parameters below are almost identical with these plugins.
916 type dshare # Direct sharing
917 ipc_key INT # unique IPC key
918 ipc_key_add_uid BOOL # add current uid to unique IPC key
919 ipc_perm INT # IPC permissions (octal, default 0600)
920 hw_ptr_alignment STR # Slave application and hw pointer alignment type
921 # STR can be one of the below strings :
928 slave { # Slave definition
929 pcm STR # slave PCM name
931 pcm { } # slave PCM definition
932 format STR # format definition
933 rate INT # rate definition
935 period_time INT # in usec
937 period_size INT # in bytes
938 buffer_time INT # in usec
940 buffer_size INT # in bytes
941 periods INT # when buffer_size or buffer_time is not specified
943 bindings { # note: this is client independent!!!
944 N INT # maps slave channel to client channel N
946 slowptr BOOL # slow but more precise pointer updates
950 <code>hw_ptr_alignment</code> specifies slave application and hw
951 pointer alignment type. By default hw_ptr_alignment is auto. Below are
952 the possible configurations:
953 - no: minimal latency with minimal frames dropped at startup. But
954 wakeup of application (return from snd_pcm_wait() or poll()) can
955 take up to 2 * period.
956 - roundup: It is guaranteed that all frames will be played at
957 startup. But the latency will increase upto period-1 frames.
958 - rounddown: It is guaranteed that a wakeup will happen for each
959 period and frames can be written from application. But on startup
960 upto period-1 frames will be dropped.
961 - auto: Selects the best approach depending on the used period and
963 If the application buffer size is < 2 * application period,
964 "roundup" will be selected to avoid under runs. If the slave_period
965 is < 10ms we could expect that there are low latency
966 requirements. Therefore "rounddown" will be chosen to avoid long
967 wakeup times. Such wakeup delay could otherwise end up with Xruns in
968 case of a dependency to another sound device (e.g. forwarding of
969 microphone to speaker). Else "no" will be chosen.
971 \subsection pcm_plugins_dshare_funcref Function reference
974 <LI>snd_pcm_dshare_open()
975 <LI>_snd_pcm_dshare_open()
981 * \brief Creates a new dshare PCM
982 * \param pcmp Returns created PCM handle
983 * \param name Name of PCM
984 * \param root Root configuration node
985 * \param conf Configuration node with dshare PCM description
986 * \param stream PCM Stream
987 * \param mode PCM Mode
988 * \warning Using of this function might be dangerous in the sense
989 * of compatibility reasons. The prototype might be freely
992 int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name,
993 snd_config_t *root, snd_config_t *conf,
994 snd_pcm_stream_t stream, int mode)
997 struct slave_params params;
998 struct snd_pcm_direct_open_conf dopen;
1002 err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
1006 /* the default settings, it might be invalid for some hardware */
1007 params.format = SND_PCM_FORMAT_S16;
1008 params.rate = 48000;
1009 params.channels = 2;
1010 params.period_time = -1;
1011 params.buffer_time = -1;
1014 err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
1015 SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format,
1016 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
1017 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
1018 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
1019 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
1020 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
1021 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
1022 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
1026 /* set a reasonable default */
1027 if (psize == -1 && params.period_time == -1)
1028 params.period_time = 125000; /* 0.125 seconds */
1030 if (params.format == -2)
1031 params.format = SND_PCM_FORMAT_UNKNOWN;
1033 params.period_size = psize;
1034 params.buffer_size = bsize;
1036 err = snd_pcm_dshare_open(pcmp, name, &dopen, ¶ms,
1037 root, sconf, stream, mode);
1038 snd_config_delete(sconf);
1042 SND_DLSYM_BUILD_VERSION(_snd_pcm_dshare_open, SND_PCM_DLSYM_VERSION);