4 * \brief PCM Direct Stream Mixing (dmix) Plugin Interface
5 * \author Jaroslav Kysela <perex@suse.cz>
9 * PCM - Direct Stream Mixing
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
37 #include <sys/ioctl.h>
42 #include <sys/socket.h>
45 #include "pcm_direct.h"
48 /* entry for static linking */
49 const char *_snd_module_pcm_dmix = "";
52 /* start is pending - this state happens when rate plugin does a delayed commit */
53 #define STATE_RUN_PENDING 1024
59 static int shm_sum_discard(snd_pcm_direct_t *dmix);
62 * sum ring buffer shared memory area
64 static int shm_sum_create_or_connect(snd_pcm_direct_t *dmix)
70 size = dmix->shmptr->s.channels *
71 dmix->shmptr->s.buffer_size *
74 dmix->u.dmix.shmid_sum = shmget(dmix->ipc_key + 1, size, IPC_CREAT | 0666);
76 if (dmix->u.dmix.shmid_sum < 0){
78 if ((tmpid = shmget(dmix->ipc_key + 1, 0, 0666)) != -1)
79 if (!shmctl(tmpid, IPC_STAT, &buf))
81 /* no users so destroy the segment */
82 if (!shmctl(tmpid, IPC_RMID, NULL))
86 dmix->u.dmix.sum_buffer = shmat(dmix->u.dmix.shmid_sum, 0, 0);
87 if (dmix->u.dmix.sum_buffer == (void *) -1) {
88 shm_sum_discard(dmix);
91 mlock(dmix->u.dmix.sum_buffer, size);
95 static int shm_sum_discard(snd_pcm_direct_t *dmix)
100 if (dmix->u.dmix.shmid_sum < 0)
102 if (dmix->u.dmix.sum_buffer != (void *) -1 && shmdt(dmix->u.dmix.sum_buffer) < 0)
104 dmix->u.dmix.sum_buffer = (void *) -1;
105 if (shmctl(dmix->u.dmix.shmid_sum, IPC_STAT, &buf) < 0)
107 if (buf.shm_nattch == 0) { /* we're the last user, destroy the segment */
108 if (shmctl(dmix->u.dmix.shmid_sum, IPC_RMID, NULL) < 0)
112 dmix->u.dmix.shmid_sum = -1;
116 static void dmix_server_free(snd_pcm_direct_t *dmix)
118 /* remove the memory region */
119 shm_sum_create_or_connect(dmix);
120 shm_sum_discard(dmix);
124 * the main function of this plugin: mixing
125 * FIXME: optimize it for different architectures
128 #if defined(__i386__)
129 #include "pcm_dmix_i386.c"
130 #elif defined(__x86_64__)
131 #include "pcm_dmix_x86_64.c"
133 #include "pcm_dmix_generic.c"
136 static void mix_areas(snd_pcm_direct_t *dmix,
137 const snd_pcm_channel_area_t *src_areas,
138 const snd_pcm_channel_area_t *dst_areas,
139 snd_pcm_uframes_t src_ofs,
140 snd_pcm_uframes_t dst_ofs,
141 snd_pcm_uframes_t size)
143 volatile signed int *sum;
144 unsigned int src_step, dst_step;
145 unsigned int chn, dchn, channels;
147 channels = dmix->channels;
148 if (dmix->shmptr->s.format == SND_PCM_FORMAT_S16) {
150 volatile signed short *dst;
151 if (dmix->interleaved) {
153 * process all areas in one loop
154 * it optimizes the memory accesses for this case
156 dmix->u.dmix.mix_areas1(size * channels,
157 ((signed short *)dst_areas[0].addr) + (dst_ofs * channels),
158 ((signed short *)src_areas[0].addr) + (src_ofs * channels),
159 dmix->u.dmix.sum_buffer + (dst_ofs * channels),
160 sizeof(signed short),
161 sizeof(signed short),
165 for (chn = 0; chn < channels; chn++) {
166 dchn = dmix->bindings ? dmix->bindings[chn] : chn;
167 if (dchn >= dmix->shmptr->s.channels)
169 src_step = src_areas[chn].step / 8;
170 dst_step = dst_areas[dchn].step / 8;
171 src = (signed short *)(((char *)src_areas[chn].addr + src_areas[chn].first / 8) + (src_ofs * src_step));
172 dst = (signed short *)(((char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + (dst_ofs * dst_step));
173 sum = dmix->u.dmix.sum_buffer + channels * dst_ofs + chn;
174 dmix->u.dmix.mix_areas1(size, dst, src, sum, dst_step, src_step, channels * sizeof(signed int));
178 volatile signed int *dst;
179 if (dmix->interleaved) {
181 * process all areas in one loop
182 * it optimizes the memory accesses for this case
184 dmix->u.dmix.mix_areas2(size * channels,
185 ((signed int *)dst_areas[0].addr) + (dst_ofs * channels),
186 ((signed int *)src_areas[0].addr) + (src_ofs * channels),
187 dmix->u.dmix.sum_buffer + (dst_ofs * channels),
193 for (chn = 0; chn < channels; chn++) {
194 dchn = dmix->bindings ? dmix->bindings[chn] : chn;
195 if (dchn >= dmix->shmptr->s.channels)
197 src_step = src_areas[chn].step / 8;
198 dst_step = dst_areas[dchn].step / 8;
199 src = (signed int *)(((char *)src_areas[chn].addr + src_areas[chn].first / 8) + (src_ofs * src_step));
200 dst = (signed int *)(((char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + (dst_ofs * dst_step));
201 sum = dmix->u.dmix.sum_buffer + channels * dst_ofs + chn;
202 dmix->u.dmix.mix_areas2(size, dst, src, sum, dst_step, src_step, channels * sizeof(signed int));
208 * if no concurrent access is allowed in the mixing routines, we need to protect
209 * the area via semaphore
211 #ifdef NO_CONCURRENT_ACCESS
212 #define dmix_down_sem(dmix) snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT)
213 #define dmix_up_sem(dmix) snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT)
215 #define dmix_down_sem(dmix)
216 #define dmix_up_sem(dmix)
220 * synchronize shm ring buffer with hardware
222 static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm, snd_pcm_uframes_t size)
224 snd_pcm_direct_t *dmix = pcm->private_data;
225 snd_pcm_uframes_t appl_ptr, slave_appl_ptr, transfer;
226 const snd_pcm_channel_area_t *src_areas, *dst_areas;
228 /* get the start of update area */
229 appl_ptr = dmix->appl_ptr - size;
230 if (appl_ptr > pcm->boundary)
231 appl_ptr += pcm->boundary;
232 appl_ptr %= pcm->buffer_size;
233 /* add sample areas here */
234 src_areas = snd_pcm_mmap_areas(pcm);
235 dst_areas = snd_pcm_mmap_areas(dmix->spcm);
236 slave_appl_ptr = dmix->slave_appl_ptr % dmix->shmptr->s.buffer_size;
237 dmix->slave_appl_ptr += size;
238 dmix->slave_appl_ptr %= dmix->shmptr->s.boundary;
241 transfer = appl_ptr + size > pcm->buffer_size ? pcm->buffer_size - appl_ptr : size;
242 if (slave_appl_ptr + transfer > dmix->shmptr->s.buffer_size)
243 transfer = dmix->shmptr->s.buffer_size - slave_appl_ptr;
246 mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
247 if (transfer >= size)
250 slave_appl_ptr += transfer;
251 slave_appl_ptr %= dmix->shmptr->s.buffer_size;
252 appl_ptr += transfer;
253 appl_ptr %= pcm->buffer_size;
259 * synchronize hardware pointer (hw_ptr) with ours
261 static int _snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm, int do_slave_sync)
263 snd_pcm_direct_t *dmix = pcm->private_data;
264 snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail;
265 snd_pcm_sframes_t diff;
267 switch (snd_pcm_state(dmix->spcm)) {
268 case SND_PCM_STATE_DISCONNECTED:
269 dmix->state = SND_PCM_STATE_DISCONNECTED;
275 snd_pcm_hwsync(dmix->spcm);
276 old_slave_hw_ptr = dmix->slave_hw_ptr;
277 slave_hw_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
278 diff = slave_hw_ptr - old_slave_hw_ptr;
279 if (diff == 0) /* fast path */
281 if (dmix->state != SND_PCM_STATE_RUNNING &&
282 dmix->state != SND_PCM_STATE_DRAINING)
283 /* not really started yet - don't update hw_ptr */
286 slave_hw_ptr += dmix->shmptr->s.boundary;
287 diff = slave_hw_ptr - old_slave_hw_ptr;
289 dmix->hw_ptr += diff;
290 dmix->hw_ptr %= pcm->boundary;
291 if (pcm->stop_threshold >= pcm->boundary) /* don't care */
293 avail = snd_pcm_mmap_playback_avail(pcm);
294 if (avail > dmix->avail_max)
295 dmix->avail_max = avail;
296 if (avail >= pcm->stop_threshold) {
298 snd_pcm_direct_timer_stop(dmix);
299 gettimeofday(&tv, 0);
300 dmix->trigger_tstamp.tv_sec = tv.tv_sec;
301 dmix->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
302 if (dmix->state == SND_PCM_STATE_RUNNING) {
303 dmix->state = SND_PCM_STATE_XRUN;
306 dmix->state = SND_PCM_STATE_SETUP;
311 static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
313 snd_pcm_direct_t *dmix = pcm->private_data;
314 return _snd_pcm_dmix_sync_ptr(pcm, dmix->slowptr);
318 * plugin implementation
321 static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm)
323 snd_pcm_direct_t *dmix = pcm->private_data;
324 snd_pcm_state_t state;
325 state = snd_pcm_state(dmix->spcm);
327 case SND_PCM_STATE_SUSPENDED:
329 case SND_PCM_STATE_DISCONNECTED:
334 if (dmix->state == STATE_RUN_PENDING)
335 return SNDRV_PCM_STATE_RUNNING;
339 static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
341 snd_pcm_direct_t *dmix = pcm->private_data;
343 switch (dmix->state) {
344 case SNDRV_PCM_STATE_DRAINING:
345 case SNDRV_PCM_STATE_RUNNING:
346 snd_pcm_dmix_sync_ptr(pcm);
351 memset(status, 0, sizeof(*status));
352 status->state = snd_pcm_dmix_state(pcm);
353 status->trigger_tstamp = dmix->trigger_tstamp;
354 status->tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm);
355 status->avail = snd_pcm_mmap_playback_avail(pcm);
356 status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max;
361 static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
363 snd_pcm_direct_t *dmix = pcm->private_data;
366 switch(dmix->state) {
367 case SNDRV_PCM_STATE_DRAINING:
368 case SNDRV_PCM_STATE_RUNNING:
369 err = snd_pcm_dmix_sync_ptr(pcm);
373 case SNDRV_PCM_STATE_PREPARED:
374 case SNDRV_PCM_STATE_SUSPENDED:
375 case STATE_RUN_PENDING:
376 *delayp = snd_pcm_mmap_playback_hw_avail(pcm);
378 case SNDRV_PCM_STATE_XRUN:
380 case SNDRV_PCM_STATE_DISCONNECTED:
387 static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm)
389 snd_pcm_direct_t *dmix = pcm->private_data;
391 switch(dmix->state) {
392 case SNDRV_PCM_STATE_DRAINING:
393 case SNDRV_PCM_STATE_RUNNING:
395 return _snd_pcm_dmix_sync_ptr(pcm, 1);
396 case SNDRV_PCM_STATE_PREPARED:
397 case SNDRV_PCM_STATE_SUSPENDED:
398 case STATE_RUN_PENDING:
400 case SNDRV_PCM_STATE_XRUN:
402 case SNDRV_PCM_STATE_DISCONNECTED:
409 static int snd_pcm_dmix_prepare(snd_pcm_t *pcm)
411 snd_pcm_direct_t *dmix = pcm->private_data;
413 snd_pcm_direct_check_interleave(dmix, pcm);
414 // assert(pcm->boundary == dmix->shmptr->s.boundary); /* for sure */
415 dmix->state = SND_PCM_STATE_PREPARED;
418 return snd_pcm_direct_set_timer_params(dmix);
421 static int snd_pcm_dmix_reset(snd_pcm_t *pcm)
423 snd_pcm_direct_t *dmix = pcm->private_data;
424 dmix->hw_ptr %= pcm->period_size;
425 dmix->appl_ptr = dmix->hw_ptr;
426 dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
430 static int snd_pcm_dmix_start_timer(snd_pcm_direct_t *dmix)
434 snd_pcm_hwsync(dmix->spcm);
435 dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
436 err = snd_timer_start(dmix->timer);
439 dmix->state = SND_PCM_STATE_RUNNING;
443 static int snd_pcm_dmix_start(snd_pcm_t *pcm)
445 snd_pcm_direct_t *dmix = pcm->private_data;
446 snd_pcm_sframes_t avail;
450 if (dmix->state != SND_PCM_STATE_PREPARED)
452 avail = snd_pcm_mmap_playback_hw_avail(pcm);
454 dmix->state = STATE_RUN_PENDING;
458 if (avail > (snd_pcm_sframes_t)pcm->buffer_size)
459 avail = pcm->buffer_size;
460 if ((err = snd_pcm_dmix_start_timer(dmix)) < 0)
462 snd_pcm_dmix_sync_area(pcm, avail);
464 gettimeofday(&tv, 0);
465 dmix->trigger_tstamp.tv_sec = tv.tv_sec;
466 dmix->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
470 static int snd_pcm_dmix_drop(snd_pcm_t *pcm)
472 snd_pcm_direct_t *dmix = pcm->private_data;
473 if (dmix->state == SND_PCM_STATE_OPEN)
475 snd_pcm_direct_timer_stop(dmix);
476 dmix->state = SND_PCM_STATE_SETUP;
480 static int snd_pcm_dmix_drain(snd_pcm_t *pcm)
482 snd_pcm_direct_t *dmix = pcm->private_data;
483 snd_pcm_uframes_t stop_threshold;
486 if (dmix->state == SND_PCM_STATE_OPEN)
488 if (pcm->mode & SND_PCM_NONBLOCK)
490 if (dmix->state == SND_PCM_STATE_PREPARED &&
491 snd_pcm_mmap_playback_hw_avail(pcm) > 0)
492 snd_pcm_dmix_start(pcm);
493 stop_threshold = pcm->stop_threshold;
494 if (pcm->stop_threshold > pcm->buffer_size)
495 pcm->stop_threshold = pcm->buffer_size;
496 dmix->state = SND_PCM_STATE_DRAINING;
498 err = snd_pcm_dmix_sync_ptr(pcm);
500 snd_pcm_dmix_drop(pcm);
503 if (dmix->state == SND_PCM_STATE_DRAINING) {
504 snd_pcm_wait_nocheck(pcm, -1);
505 snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */
507 } while (dmix->state == SND_PCM_STATE_DRAINING);
508 pcm->stop_threshold = stop_threshold;
512 static int snd_pcm_dmix_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
517 static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_uframes_t frames ATTRIBUTE_UNUSED)
520 /* FIXME: substract samples from the mix ring buffer, too? */
521 snd_pcm_mmap_appl_backward(pcm, frames);
528 static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
530 snd_pcm_sframes_t avail;
532 avail = snd_pcm_mmap_playback_avail(pcm);
535 if (frames > (snd_pcm_uframes_t)avail)
537 snd_pcm_mmap_appl_forward(pcm, frames);
541 static int snd_pcm_dmix_resume(snd_pcm_t *pcm)
543 snd_pcm_direct_t *dmix = pcm->private_data;
544 snd_pcm_resume(dmix->spcm);
548 static snd_pcm_sframes_t snd_pcm_dmix_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
553 static snd_pcm_sframes_t snd_pcm_dmix_readn(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
558 static int snd_pcm_dmix_close(snd_pcm_t *pcm)
560 snd_pcm_direct_t *dmix = pcm->private_data;
563 snd_timer_close(dmix->timer);
564 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
565 snd_pcm_close(dmix->spcm);
567 snd_pcm_direct_server_discard(dmix);
569 snd_pcm_direct_client_discard(dmix);
570 shm_sum_discard(dmix);
571 if (snd_pcm_direct_shm_discard(dmix) > 0) {
572 if (snd_pcm_direct_semaphore_discard(dmix) < 0)
573 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
575 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
578 free(dmix->bindings);
579 pcm->private_data = NULL;
584 static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
585 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
586 snd_pcm_uframes_t size)
588 snd_pcm_direct_t *dmix = pcm->private_data;
591 switch (snd_pcm_state(dmix->spcm)) {
592 case SND_PCM_STATE_XRUN:
594 case SND_PCM_STATE_SUSPENDED:
601 snd_pcm_mmap_appl_forward(pcm, size);
602 if (dmix->state == STATE_RUN_PENDING) {
603 if ((err = snd_pcm_dmix_start_timer(dmix)) < 0)
605 } else if (dmix->state == SND_PCM_STATE_RUNNING ||
606 dmix->state == SND_PCM_STATE_DRAINING)
607 _snd_pcm_dmix_sync_ptr(pcm, 1);
608 if (dmix->state == SND_PCM_STATE_RUNNING ||
609 dmix->state == SND_PCM_STATE_DRAINING) {
610 /* ok, we commit the changes after the validation of area */
611 /* it's intended, although the result might be crappy */
612 snd_pcm_dmix_sync_area(pcm, size);
613 /* clear timer queue to avoid a bogus return from poll */
614 if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
615 snd_pcm_direct_clear_timer_queue(dmix);
620 static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm)
622 snd_pcm_direct_t *dmix = pcm->private_data;
624 if (dmix->state == SND_PCM_STATE_RUNNING ||
625 dmix->state == SND_PCM_STATE_DRAINING)
626 snd_pcm_dmix_sync_ptr(pcm);
627 return snd_pcm_mmap_playback_avail(pcm);
630 static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out)
632 snd_pcm_direct_t *dmix = pcm->private_data;
634 snd_output_printf(out, "Direct Stream Mixing PCM\n");
636 snd_output_printf(out, "\nIts setup is:\n");
637 snd_pcm_dump_setup(pcm, out);
640 snd_pcm_dump(dmix->spcm, out);
643 static snd_pcm_ops_t snd_pcm_dmix_ops = {
644 .close = snd_pcm_dmix_close,
645 .info = snd_pcm_direct_info,
646 .hw_refine = snd_pcm_direct_hw_refine,
647 .hw_params = snd_pcm_direct_hw_params,
648 .hw_free = snd_pcm_direct_hw_free,
649 .sw_params = snd_pcm_direct_sw_params,
650 .channel_info = snd_pcm_direct_channel_info,
651 .dump = snd_pcm_dmix_dump,
652 .nonblock = snd_pcm_direct_nonblock,
653 .async = snd_pcm_direct_async,
654 .poll_revents = snd_pcm_direct_poll_revents,
655 .mmap = snd_pcm_direct_mmap,
656 .munmap = snd_pcm_direct_munmap,
659 static snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
660 .status = snd_pcm_dmix_status,
661 .state = snd_pcm_dmix_state,
662 .hwsync = snd_pcm_dmix_hwsync,
663 .delay = snd_pcm_dmix_delay,
664 .prepare = snd_pcm_dmix_prepare,
665 .reset = snd_pcm_dmix_reset,
666 .start = snd_pcm_dmix_start,
667 .drop = snd_pcm_dmix_drop,
668 .drain = snd_pcm_dmix_drain,
669 .pause = snd_pcm_dmix_pause,
670 .rewind = snd_pcm_dmix_rewind,
671 .forward = snd_pcm_dmix_forward,
672 .resume = snd_pcm_dmix_resume,
677 .writei = snd_pcm_mmap_writei,
678 .writen = snd_pcm_mmap_writen,
679 .readi = snd_pcm_dmix_readi,
680 .readn = snd_pcm_dmix_readn,
681 .avail_update = snd_pcm_dmix_avail_update,
682 .mmap_commit = snd_pcm_dmix_mmap_commit,
686 * \brief Creates a new dmix PCM
687 * \param pcmp Returns created PCM handle
688 * \param name Name of PCM
689 * \param ipc_key IPC key for semaphore and shared memory
690 * \param ipc_perm IPC permissions for semaphore and shared memory
691 * \param params Parameters for slave
692 * \param bindings Channel bindings
693 * \param slowptr Slow but more precise pointer updates
694 * \param root Configuration root
695 * \param sconf Slave configuration
696 * \param stream PCM Direction (stream)
697 * \param mode PCM Mode
698 * \retval zero on success otherwise a negative error code
699 * \warning Using of this function might be dangerous in the sense
700 * of compatibility reasons. The prototype might be freely
703 int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
704 key_t ipc_key, mode_t ipc_perm,
705 struct slave_params *params,
706 snd_config_t *bindings,
708 snd_config_t *root, snd_config_t *sconf,
709 snd_pcm_stream_t stream, int mode)
711 snd_pcm_t *pcm = NULL, *spcm = NULL;
712 snd_pcm_direct_t *dmix = NULL;
713 int ret, first_instance;
714 int fail_sem_loop = 10;
718 if (stream != SND_PCM_STREAM_PLAYBACK) {
719 SNDERR("The dmix plugin supports only playback stream");
723 dmix = calloc(1, sizeof(snd_pcm_direct_t));
729 ret = snd_pcm_direct_parse_bindings(dmix, bindings);
733 dmix->ipc_key = ipc_key;
734 dmix->ipc_perm = ipc_perm;
738 ret = snd_pcm_new(&pcm, dmix->type = SND_PCM_TYPE_DMIX, name, stream, mode);
744 ret = snd_pcm_direct_semaphore_create_or_connect(dmix);
746 SNDERR("unable to create IPC semaphore");
749 ret = snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
751 snd_pcm_direct_semaphore_discard(dmix);
752 if (--fail_sem_loop <= 0)
759 first_instance = ret = snd_pcm_direct_shm_create_or_connect(dmix);
761 SNDERR("unable to create IPC shm instance");
765 pcm->ops = &snd_pcm_dmix_ops;
766 pcm->fast_ops = &snd_pcm_dmix_fast_ops;
767 pcm->private_data = dmix;
768 dmix->state = SND_PCM_STATE_OPEN;
769 dmix->slowptr = slowptr;
770 dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
772 if (first_instance) {
773 ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
775 SNDERR("unable to open slave");
779 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
780 SNDERR("dmix plugin can be only connected to hw plugin");
785 ret = snd_pcm_direct_initialize_slave(dmix, spcm, params);
787 SNDERR("unable to initialize slave");
793 dmix->server_free = dmix_server_free;
795 ret = snd_pcm_direct_server_create(dmix);
797 SNDERR("unable to create server");
801 dmix->shmptr->type = spcm->type;
803 ret = snd_pcm_direct_client_connect(dmix);
805 SNDERR("unable to connect client");
809 ret = snd_pcm_hw_open_fd(&spcm, "dmix_client", dmix->hw_fd, 0, 0);
811 SNDERR("unable to open hardware");
815 spcm->donot_close = 1;
817 spcm->buffer_size = dmix->shmptr->s.buffer_size;
818 spcm->sample_bits = dmix->shmptr->s.sample_bits;
819 spcm->channels = dmix->shmptr->s.channels;
820 spcm->format = dmix->shmptr->s.format;
821 spcm->boundary = dmix->shmptr->s.boundary;
822 spcm->info = dmix->shmptr->s.info;
823 ret = snd_pcm_mmap(spcm);
825 SNDERR("unable to mmap channels");
831 ret = shm_sum_create_or_connect(dmix);
833 SNDERR("unable to initialize sum ring buffer");
837 ret = snd_pcm_direct_initialize_poll_fd(dmix);
839 SNDERR("unable to initialize poll_fd");
843 mix_select_callbacks(dmix);
845 pcm->poll_fd = dmix->poll_fd;
846 pcm->poll_events = POLLIN; /* it's different than other plugins */
849 snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0);
850 snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0);
852 if (dmix->channels == UINT_MAX)
853 dmix->channels = dmix->shmptr->s.channels;
855 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
863 snd_timer_close(dmix->timer);
865 snd_pcm_direct_server_discard(dmix);
867 snd_pcm_direct_client_discard(dmix);
870 if (dmix->u.dmix.shmid_sum >= 0)
871 shm_sum_discard(dmix);
872 if (dmix->shmid >= 0) {
873 if (snd_pcm_direct_shm_discard(dmix) > 0) {
874 if (dmix->semid >= 0) {
875 if (snd_pcm_direct_semaphore_discard(dmix) < 0)
876 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
881 free(dmix->bindings);
889 /*! \page pcm_plugins
891 \section pcm_plugins_dmix Plugin: dmix
893 This plugin provides direct mixing of multiple streams. The resolution
894 for 32-bit mixing is only 24-bit. The low significant byte is filled with
895 zeros. The extra 8 bits are used for the saturation.
899 type dmix # Direct mix
900 ipc_key INT # unique IPC key
901 ipc_key_add_uid BOOL # add current uid to unique IPC key
902 ipc_perm INT # IPC permissions (octal, default 0600)
905 slave { # Slave definition
906 pcm STR # slave PCM name
908 pcm { } # slave PCM definition
909 format STR # format definition
910 rate INT # rate definition
912 period_time INT # in usec
914 period_size INT # in bytes
915 buffer_time INT # in usec
917 buffer_size INT # in bytes
918 periods INT # when buffer_size or buffer_time is not specified
920 bindings { # note: this is client independent!!!
921 N INT # maps slave channel to client channel N
923 slowptr BOOL # slow but more precise pointer updates
927 <code>ipc_key</code> specfies the unique IPC key in integer.
928 This number must be unique for each different dmix definition,
929 since the shared memory is created with this key number.
930 When <code>ipc_key_add_uid</code> is set true, the uid value is
931 added to the value set in <code>ipc_key</code>. This will
932 avoid the confliction of the same IPC key with different users
935 Note that the dmix plugin itself supports only a single configuration.
936 That is, it supports only the fixed rate (default 48000), format
937 (\c S16), channels (2), and period_time (125000).
938 For using other configuration, you have to set the value explicitly
939 in the slave PCM definition. The rate, format and channels can be
940 covered by an additional \ref pcm_plugins_dmix "plug plugin",
941 but there is only one base configuration, anyway.
943 An example configuration for setting 44100 Hz, \c S32_LE format
944 as the slave PCM of "hw:0" is like below:
948 ipc_key 321456 # any unique value
957 You can hear 48000 Hz samples still using this dmix pcm via plug plugin
960 % aplay -Dplug:dmix_44 foo_48k.wav
963 For using the dmix plugin for OSS emulation device, you have to set
964 the period and the buffer sizes in power of two. For example,
968 ipc_key 321456 # any unique value
973 period_size 1024 # must be power of 2
974 buffer_size 8192 # ditto
978 <code>period_time 0</code> must be set, too, for resetting the
979 default value. In the case of soundcards with multi-channel IO,
980 adding the bindings would help
985 0 0 # map from 0 to 0
986 1 1 # map from 1 to 1
990 so that only the first two channels are used by dmix.
991 Also, note that ICE1712 have the limited buffer size, 5513 frames
992 (corresponding to 640 kB). In this case, reduce the buffer_size
995 \subsection pcm_plugins_dmix_funcref Function reference
998 <LI>snd_pcm_dmix_open()
999 <LI>_snd_pcm_dmix_open()
1005 * \brief Creates a new dmix PCM
1006 * \param pcmp Returns created PCM handle
1007 * \param name Name of PCM
1008 * \param root Root configuration node
1009 * \param conf Configuration node with dmix PCM description
1010 * \param stream PCM Stream
1011 * \param mode PCM Mode
1012 * \warning Using of this function might be dangerous in the sense
1013 * of compatibility reasons. The prototype might be freely
1014 * changed in future.
1016 int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
1017 snd_config_t *root, snd_config_t *conf,
1018 snd_pcm_stream_t stream, int mode)
1020 snd_config_iterator_t i, next;
1021 snd_config_t *slave = NULL, *bindings = NULL, *sconf;
1022 struct slave_params params;
1023 int bsize, psize, ipc_key_add_uid = 0, slowptr = 0;
1025 mode_t ipc_perm = 0600;
1027 snd_config_for_each(i, next, conf) {
1028 snd_config_t *n = snd_config_iterator_entry(i);
1030 if (snd_config_get_id(n, &id) < 0)
1032 if (snd_pcm_conf_generic_id(id))
1034 if (strcmp(id, "ipc_key") == 0) {
1036 err = snd_config_get_integer(n, &key);
1038 SNDERR("The field ipc_key must be an integer type");
1044 if (strcmp(id, "ipc_perm") == 0) {
1047 err = snd_config_get_ascii(n, &perm);
1049 SNDERR("The field ipc_perm must be a valid file permission");
1052 if (isdigit(*perm) == 0) {
1053 SNDERR("The field ipc_perm must be a valid file permission");
1056 ipc_perm = strtol(perm, &endp, 8);
1059 if (strcmp(id, "ipc_key_add_uid") == 0) {
1060 if ((err = snd_config_get_bool(n)) < 0) {
1061 SNDERR("The field ipc_key_add_uid must be a boolean type");
1064 ipc_key_add_uid = err;
1067 if (strcmp(id, "slave") == 0) {
1071 if (strcmp(id, "bindings") == 0) {
1075 if (strcmp(id, "slowptr") == 0) {
1076 err = snd_config_get_bool(n);
1082 SNDERR("Unknown field %s", id);
1086 SNDERR("slave is not defined");
1089 if (ipc_key_add_uid)
1090 ipc_key += getuid();
1092 SNDERR("Unique IPC key is not defined");
1095 /* the default settings, it might be invalid for some hardware */
1096 params.format = SND_PCM_FORMAT_S16;
1097 params.rate = 48000;
1098 params.channels = 2;
1099 params.period_time = -1;
1100 params.buffer_time = -1;
1104 err = snd_pcm_slave_conf(root, slave, &sconf, 8,
1105 SND_PCM_HW_PARAM_FORMAT, 0, ¶ms.format,
1106 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
1107 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
1108 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
1109 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
1110 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
1111 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
1112 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
1116 /* set a reasonable default */
1117 if (psize == -1 && params.period_time == -1)
1118 params.period_time = 125000; /* 0.125 seconds */
1120 /* sorry, limited features */
1121 if (params.format != SND_PCM_FORMAT_S16 &&
1122 params.format != SND_PCM_FORMAT_S32) {
1123 SNDERR("invalid format, specify s16 or s32");
1124 snd_config_delete(sconf);
1128 params.period_size = psize;
1129 params.buffer_size = bsize;
1131 err = snd_pcm_dmix_open(pcmp, name, ipc_key, ipc_perm, ¶ms, bindings, slowptr, root, sconf, stream, mode);
1133 snd_config_delete(sconf);
1137 SND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION);