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 = "";
57 * sum ring buffer shared memory area
59 static int shm_sum_create_or_connect(snd_pcm_direct_t *dmix)
61 static int shm_sum_discard(snd_pcm_direct_t *dmix);
66 size = dmix->shmptr->s.channels *
67 dmix->shmptr->s.buffer_size *
70 dmix->u.dmix.shmid_sum = shmget(dmix->ipc_key + 1, size, IPC_CREAT | 0666);
72 if (dmix->u.dmix.shmid_sum < 0){
74 if ((tmpid = shmget(dmix->ipc_key + 1, 0, 0666)) != -1)
75 if (!shmctl(tmpid, IPC_STAT, &buf))
77 /* no users so destroy the segment */
78 if (!shmctl(tmpid, IPC_RMID, NULL))
82 dmix->u.dmix.sum_buffer = shmat(dmix->u.dmix.shmid_sum, 0, 0);
83 if (dmix->u.dmix.sum_buffer == (void *) -1) {
84 shm_sum_discard(dmix);
87 mlock(dmix->u.dmix.sum_buffer, size);
91 static int shm_sum_discard(snd_pcm_direct_t *dmix)
96 if (dmix->u.dmix.shmid_sum < 0)
98 if (dmix->u.dmix.sum_buffer != (void *) -1 && shmdt(dmix->u.dmix.sum_buffer) < 0)
100 dmix->u.dmix.sum_buffer = (void *) -1;
101 if (shmctl(dmix->u.dmix.shmid_sum, IPC_STAT, &buf) < 0)
103 if (buf.shm_nattch == 0) { /* we're the last user, destroy the segment */
104 if (shmctl(dmix->u.dmix.shmid_sum, IPC_RMID, NULL) < 0)
108 dmix->u.dmix.shmid_sum = -1;
112 static void dmix_server_free(snd_pcm_direct_t *dmix)
114 /* remove the memory region */
115 shm_sum_create_or_connect(dmix);
116 shm_sum_discard(dmix);
120 * the main function of this plugin: mixing
121 * FIXME: optimize it for different architectures
124 #if defined(__i386__)
125 #include "pcm_dmix_i386.c"
126 #elif defined(__x86_64__)
127 #include "pcm_dmix_x86_64.c"
129 #include "pcm_dmix_generic.c"
132 static void mix_areas(snd_pcm_direct_t *dmix,
133 const snd_pcm_channel_area_t *src_areas,
134 const snd_pcm_channel_area_t *dst_areas,
135 snd_pcm_uframes_t src_ofs,
136 snd_pcm_uframes_t dst_ofs,
137 snd_pcm_uframes_t size)
139 volatile signed int *sum;
140 unsigned int src_step, dst_step;
141 unsigned int chn, dchn, channels;
143 channels = dmix->channels;
144 if (dmix->shmptr->s.format == SND_PCM_FORMAT_S16) {
146 volatile signed short *dst;
147 if (dmix->interleaved) {
149 * process all areas in one loop
150 * it optimizes the memory accesses for this case
152 dmix->u.dmix.mix_areas1(size * channels,
153 ((signed short *)dst_areas[0].addr) + (dst_ofs * channels),
154 ((signed short *)src_areas[0].addr) + (src_ofs * channels),
155 dmix->u.dmix.sum_buffer + (dst_ofs * channels),
156 sizeof(signed short),
157 sizeof(signed short),
161 for (chn = 0; chn < channels; chn++) {
162 dchn = dmix->bindings ? dmix->bindings[chn] : chn;
163 if (dchn >= dmix->shmptr->s.channels)
165 src_step = src_areas[chn].step / 8;
166 dst_step = dst_areas[dchn].step / 8;
167 src = (signed short *)(((char *)src_areas[chn].addr + src_areas[chn].first / 8) + (src_ofs * src_step));
168 dst = (signed short *)(((char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + (dst_ofs * dst_step));
169 sum = dmix->u.dmix.sum_buffer + channels * dst_ofs + chn;
170 dmix->u.dmix.mix_areas1(size, dst, src, sum, dst_step, src_step, channels * sizeof(signed int));
174 volatile signed int *dst;
175 if (dmix->interleaved) {
177 * process all areas in one loop
178 * it optimizes the memory accesses for this case
180 dmix->u.dmix.mix_areas2(size * channels,
181 ((signed int *)dst_areas[0].addr) + (dst_ofs * channels),
182 ((signed int *)src_areas[0].addr) + (src_ofs * channels),
183 dmix->u.dmix.sum_buffer + (dst_ofs * channels),
189 for (chn = 0; chn < channels; chn++) {
190 dchn = dmix->bindings ? dmix->bindings[chn] : chn;
191 if (dchn >= dmix->shmptr->s.channels)
193 src_step = src_areas[chn].step / 8;
194 dst_step = dst_areas[dchn].step / 8;
195 src = (signed int *)(((char *)src_areas[chn].addr + src_areas[chn].first / 8) + (src_ofs * src_step));
196 dst = (signed int *)(((char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + (dst_ofs * dst_step));
197 sum = dmix->u.dmix.sum_buffer + channels * dst_ofs + chn;
198 dmix->u.dmix.mix_areas2(size, dst, src, sum, dst_step, src_step, channels * sizeof(signed int));
204 * synchronize shm ring buffer with hardware
206 static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm, snd_pcm_uframes_t size)
208 snd_pcm_direct_t *dmix = pcm->private_data;
209 snd_pcm_uframes_t appl_ptr, slave_appl_ptr, transfer;
210 const snd_pcm_channel_area_t *src_areas, *dst_areas;
212 /* get the start of update area */
213 appl_ptr = dmix->appl_ptr - size;
214 if (appl_ptr > pcm->boundary)
215 appl_ptr += pcm->boundary;
216 appl_ptr %= pcm->buffer_size;
217 /* add sample areas here */
218 src_areas = snd_pcm_mmap_areas(pcm);
219 dst_areas = snd_pcm_mmap_areas(dmix->spcm);
220 slave_appl_ptr = dmix->slave_appl_ptr % dmix->shmptr->s.buffer_size;
221 dmix->slave_appl_ptr += size;
222 dmix->slave_appl_ptr %= dmix->shmptr->s.boundary;
224 transfer = appl_ptr + size > pcm->buffer_size ? pcm->buffer_size - appl_ptr : size;
225 if (slave_appl_ptr + transfer > dmix->shmptr->s.buffer_size)
226 transfer = dmix->shmptr->s.buffer_size - slave_appl_ptr;
228 mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
229 if (transfer >= size)
232 slave_appl_ptr += transfer;
233 slave_appl_ptr %= dmix->shmptr->s.buffer_size;
234 appl_ptr += transfer;
235 appl_ptr %= pcm->buffer_size;
240 * synchronize hardware pointer (hw_ptr) with ours
242 static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
244 snd_pcm_direct_t *dmix = pcm->private_data;
245 snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail;
246 snd_pcm_sframes_t diff;
248 switch (snd_pcm_state(dmix->spcm)) {
249 case SND_PCM_STATE_DISCONNECTED:
250 dmix->state = SND_PCM_STATE_DISCONNECTED;
256 snd_pcm_hwsync(dmix->spcm);
257 old_slave_hw_ptr = dmix->slave_hw_ptr;
258 slave_hw_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
259 diff = slave_hw_ptr - old_slave_hw_ptr;
260 if (diff == 0) /* fast path */
263 slave_hw_ptr += dmix->shmptr->s.boundary;
264 diff = slave_hw_ptr - old_slave_hw_ptr;
266 dmix->hw_ptr += diff;
267 dmix->hw_ptr %= pcm->boundary;
268 if (pcm->stop_threshold >= pcm->boundary) /* don't care */
270 if ((avail = snd_pcm_mmap_playback_avail(pcm)) >= pcm->stop_threshold) {
272 gettimeofday(&tv, 0);
273 dmix->trigger_tstamp.tv_sec = tv.tv_sec;
274 dmix->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
275 dmix->state = SND_PCM_STATE_XRUN;
276 dmix->avail_max = avail;
279 if (avail > dmix->avail_max)
280 dmix->avail_max = avail;
285 * plugin implementation
288 static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
290 snd_pcm_direct_t *dmix = pcm->private_data;
291 snd_pcm_state_t state;
293 switch (dmix->state) {
294 case SNDRV_PCM_STATE_DRAINING:
295 case SNDRV_PCM_STATE_RUNNING:
296 snd_pcm_dmix_sync_ptr(pcm);
301 memset(status, 0, sizeof(*status));
302 state = snd_pcm_state(dmix->spcm);
303 status->state = state == SNDRV_PCM_STATE_RUNNING ? dmix->state : state;
304 status->trigger_tstamp = dmix->trigger_tstamp;
305 status->tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm);
306 status->avail = snd_pcm_mmap_playback_avail(pcm);
307 status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max;
312 static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm)
314 snd_pcm_direct_t *dmix = pcm->private_data;
315 switch (snd_pcm_state(dmix->spcm)) {
316 case SND_PCM_STATE_SUSPENDED:
317 return SND_PCM_STATE_SUSPENDED;
318 case SND_PCM_STATE_DISCONNECTED:
319 dmix->state = SND_PCM_STATE_DISCONNECTED;
327 static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
329 snd_pcm_direct_t *dmix = pcm->private_data;
332 switch(dmix->state) {
333 case SNDRV_PCM_STATE_DRAINING:
334 case SNDRV_PCM_STATE_RUNNING:
335 err = snd_pcm_dmix_sync_ptr(pcm);
338 case SNDRV_PCM_STATE_PREPARED:
339 case SNDRV_PCM_STATE_SUSPENDED:
340 *delayp = snd_pcm_mmap_playback_hw_avail(pcm);
342 case SNDRV_PCM_STATE_XRUN:
344 case SNDRV_PCM_STATE_DISCONNECTED:
351 static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm)
353 snd_pcm_direct_t *dmix = pcm->private_data;
355 switch(dmix->state) {
356 case SNDRV_PCM_STATE_DRAINING:
357 case SNDRV_PCM_STATE_RUNNING:
358 return snd_pcm_dmix_sync_ptr(pcm);
359 case SNDRV_PCM_STATE_PREPARED:
360 case SNDRV_PCM_STATE_SUSPENDED:
362 case SNDRV_PCM_STATE_XRUN:
364 case SNDRV_PCM_STATE_DISCONNECTED:
371 static int snd_pcm_dmix_prepare(snd_pcm_t *pcm)
373 snd_pcm_direct_t *dmix = pcm->private_data;
375 snd_pcm_direct_check_interleave(dmix, pcm);
376 // assert(pcm->boundary == dmix->shmptr->s.boundary); /* for sure */
377 dmix->state = SND_PCM_STATE_PREPARED;
383 static int snd_pcm_dmix_reset(snd_pcm_t *pcm)
385 snd_pcm_direct_t *dmix = pcm->private_data;
386 dmix->hw_ptr %= pcm->period_size;
387 dmix->appl_ptr = dmix->hw_ptr;
388 dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
392 static int snd_pcm_dmix_start(snd_pcm_t *pcm)
394 snd_pcm_direct_t *dmix = pcm->private_data;
395 snd_pcm_sframes_t avail;
399 if (dmix->state != SND_PCM_STATE_PREPARED)
401 err = snd_timer_start(dmix->timer);
404 dmix->state = SND_PCM_STATE_RUNNING;
405 snd_pcm_hwsync(dmix->spcm);
406 dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
407 avail = snd_pcm_mmap_playback_hw_avail(pcm);
410 if (avail > (snd_pcm_sframes_t)pcm->buffer_size)
411 avail = pcm->buffer_size;
412 snd_pcm_dmix_sync_area(pcm, avail);
413 gettimeofday(&tv, 0);
414 dmix->trigger_tstamp.tv_sec = tv.tv_sec;
415 dmix->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
419 static int snd_pcm_dmix_drop(snd_pcm_t *pcm)
421 snd_pcm_direct_t *dmix = pcm->private_data;
422 if (dmix->state == SND_PCM_STATE_OPEN)
424 snd_timer_stop(dmix->timer);
425 dmix->state = SND_PCM_STATE_SETUP;
429 static int snd_pcm_dmix_drain(snd_pcm_t *pcm)
431 snd_pcm_direct_t *dmix = pcm->private_data;
432 snd_pcm_uframes_t stop_threshold;
435 if (dmix->state == SND_PCM_STATE_OPEN)
437 stop_threshold = pcm->stop_threshold;
438 if (pcm->stop_threshold > pcm->buffer_size)
439 pcm->stop_threshold = pcm->buffer_size;
440 if (dmix->state == SND_PCM_STATE_PREPARED &&
441 snd_pcm_mmap_playback_hw_avail(pcm) > 0)
442 snd_pcm_dmix_start(pcm);
443 while (dmix->state == SND_PCM_STATE_RUNNING) {
444 err = snd_pcm_dmix_sync_ptr(pcm);
447 if (pcm->mode & SND_PCM_NONBLOCK)
449 snd_pcm_wait(pcm, -1);
451 pcm->stop_threshold = stop_threshold;
452 return snd_pcm_dmix_drop(pcm);
455 static int snd_pcm_dmix_pause(snd_pcm_t *pcm, int enable)
457 snd_pcm_direct_t *dmix = pcm->private_data;
459 if (dmix->state != SND_PCM_STATE_RUNNING)
461 dmix->state = SND_PCM_STATE_PAUSED;
462 snd_timer_stop(dmix->timer);
464 if (dmix->state != SND_PCM_STATE_PAUSED)
466 dmix->state = SND_PCM_STATE_RUNNING;
467 snd_timer_start(dmix->timer);
472 static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
475 /* FIXME: substract samples from the mix ring buffer, too? */
476 snd_pcm_mmap_appl_backward(pcm, frames);
483 static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
485 snd_pcm_sframes_t avail;
487 avail = snd_pcm_mmap_playback_avail(pcm);
490 if (frames > (snd_pcm_uframes_t)avail)
492 snd_pcm_mmap_appl_forward(pcm, frames);
496 static int snd_pcm_dmix_resume(snd_pcm_t *pcm)
498 snd_pcm_direct_t *dmix = pcm->private_data;
499 snd_pcm_resume(dmix->spcm);
503 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)
508 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)
513 static int snd_pcm_dmix_close(snd_pcm_t *pcm)
515 snd_pcm_direct_t *dmix = pcm->private_data;
518 snd_timer_close(dmix->timer);
519 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
520 snd_pcm_close(dmix->spcm);
522 snd_pcm_direct_server_discard(dmix);
524 snd_pcm_direct_client_discard(dmix);
525 shm_sum_discard(dmix);
526 if (snd_pcm_direct_shm_discard(dmix) > 0) {
527 if (snd_pcm_direct_semaphore_discard(dmix) < 0)
528 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
530 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
533 free(dmix->bindings);
534 pcm->private_data = NULL;
539 static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
540 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
541 snd_pcm_uframes_t size)
543 snd_pcm_direct_t *dmix = pcm->private_data;
546 switch (snd_pcm_state(dmix->spcm)) {
547 case SND_PCM_STATE_XRUN:
549 case SND_PCM_STATE_SUSPENDED:
554 snd_pcm_mmap_appl_forward(pcm, size);
555 if (dmix->state == SND_PCM_STATE_RUNNING) {
556 err = snd_pcm_dmix_sync_ptr(pcm);
559 /* ok, we commit the changes after the validation of area */
560 /* it's intended, although the result might be crappy */
561 snd_pcm_dmix_sync_area(pcm, size);
566 static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
568 snd_pcm_direct_t *dmix = pcm->private_data;
571 if (dmix->state == SND_PCM_STATE_RUNNING) {
572 err = snd_pcm_dmix_sync_ptr(pcm);
576 return snd_pcm_mmap_playback_avail(pcm);
579 static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out)
581 snd_pcm_direct_t *dmix = pcm->private_data;
583 snd_output_printf(out, "Direct Stream Mixing PCM\n");
585 snd_output_printf(out, "\nIts setup is:\n");
586 snd_pcm_dump_setup(pcm, out);
589 snd_pcm_dump(dmix->spcm, out);
592 static snd_pcm_ops_t snd_pcm_dmix_ops = {
593 .close = snd_pcm_dmix_close,
594 .info = snd_pcm_direct_info,
595 .hw_refine = snd_pcm_direct_hw_refine,
596 .hw_params = snd_pcm_direct_hw_params,
597 .hw_free = snd_pcm_direct_hw_free,
598 .sw_params = snd_pcm_direct_sw_params,
599 .channel_info = snd_pcm_direct_channel_info,
600 .dump = snd_pcm_dmix_dump,
601 .nonblock = snd_pcm_direct_nonblock,
602 .async = snd_pcm_direct_async,
603 .poll_revents = snd_pcm_direct_poll_revents,
604 .mmap = snd_pcm_direct_mmap,
605 .munmap = snd_pcm_direct_munmap,
608 static snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
609 .status = snd_pcm_dmix_status,
610 .state = snd_pcm_dmix_state,
611 .hwsync = snd_pcm_dmix_hwsync,
612 .delay = snd_pcm_dmix_delay,
613 .prepare = snd_pcm_dmix_prepare,
614 .reset = snd_pcm_dmix_reset,
615 .start = snd_pcm_dmix_start,
616 .drop = snd_pcm_dmix_drop,
617 .drain = snd_pcm_dmix_drain,
618 .pause = snd_pcm_dmix_pause,
619 .rewind = snd_pcm_dmix_rewind,
620 .forward = snd_pcm_dmix_forward,
621 .resume = snd_pcm_dmix_resume,
626 .writei = snd_pcm_mmap_writei,
627 .writen = snd_pcm_mmap_writen,
628 .readi = snd_pcm_dmix_readi,
629 .readn = snd_pcm_dmix_readn,
630 .avail_update = snd_pcm_dmix_avail_update,
631 .mmap_commit = snd_pcm_dmix_mmap_commit,
635 * \brief Creates a new dmix PCM
636 * \param pcmp Returns created PCM handle
637 * \param name Name of PCM
638 * \param ipc_key IPC key for semaphore and shared memory
639 * \param ipc_perm IPC permissions for semaphore and shared memory
640 * \param params Parameters for slave
641 * \param bindings Channel bindings
642 * \param slowptr Slow but more precise pointer updates
643 * \param root Configuration root
644 * \param sconf Slave configuration
645 * \param stream PCM Direction (stream)
646 * \param mode PCM Mode
647 * \retval zero on success otherwise a negative error code
648 * \warning Using of this function might be dangerous in the sense
649 * of compatibility reasons. The prototype might be freely
652 int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
653 key_t ipc_key, mode_t ipc_perm,
654 struct slave_params *params,
655 snd_config_t *bindings,
657 snd_config_t *root, snd_config_t *sconf,
658 snd_pcm_stream_t stream, int mode)
660 snd_pcm_t *pcm = NULL, *spcm = NULL;
661 snd_pcm_direct_t *dmix = NULL;
662 int ret, first_instance;
663 int fail_sem_loop = 10;
667 if (stream != SND_PCM_STREAM_PLAYBACK) {
668 SNDERR("The dmix plugin supports only playback stream");
672 dmix = calloc(1, sizeof(snd_pcm_direct_t));
678 ret = snd_pcm_direct_parse_bindings(dmix, bindings);
682 dmix->ipc_key = ipc_key;
683 dmix->ipc_perm = ipc_perm;
687 ret = snd_pcm_new(&pcm, dmix->type = SND_PCM_TYPE_DMIX, name, stream, mode);
693 ret = snd_pcm_direct_semaphore_create_or_connect(dmix);
695 SNDERR("unable to create IPC semaphore");
698 ret = snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
700 snd_pcm_direct_semaphore_discard(dmix);
701 if (--fail_sem_loop <= 0)
708 first_instance = ret = snd_pcm_direct_shm_create_or_connect(dmix);
710 SNDERR("unable to create IPC shm instance");
714 pcm->ops = &snd_pcm_dmix_ops;
715 pcm->fast_ops = &snd_pcm_dmix_fast_ops;
716 pcm->private_data = dmix;
717 dmix->state = SND_PCM_STATE_OPEN;
718 dmix->slowptr = slowptr;
719 dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
721 if (first_instance) {
722 ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
724 SNDERR("unable to open slave");
728 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
729 SNDERR("dmix plugin can be only connected to hw plugin");
734 ret = snd_pcm_direct_initialize_slave(dmix, spcm, params);
736 SNDERR("unable to initialize slave");
742 dmix->server_free = dmix_server_free;
744 ret = snd_pcm_direct_server_create(dmix);
746 SNDERR("unable to create server");
750 dmix->shmptr->type = spcm->type;
752 ret = snd_pcm_direct_client_connect(dmix);
754 SNDERR("unable to connect client");
758 ret = snd_pcm_hw_open_fd(&spcm, "dmix_client", dmix->hw_fd, 0, 0);
760 SNDERR("unable to open hardware");
764 spcm->donot_close = 1;
766 spcm->buffer_size = dmix->shmptr->s.buffer_size;
767 spcm->sample_bits = dmix->shmptr->s.sample_bits;
768 spcm->channels = dmix->shmptr->s.channels;
769 spcm->format = dmix->shmptr->s.format;
770 spcm->boundary = dmix->shmptr->s.boundary;
771 spcm->info = dmix->shmptr->s.info;
772 ret = snd_pcm_mmap(spcm);
774 SNDERR("unable to mmap channels");
780 ret = shm_sum_create_or_connect(dmix);
782 SNDERR("unable to initialize sum ring buffer");
786 ret = snd_pcm_direct_initialize_poll_fd(dmix);
788 SNDERR("unable to initialize poll_fd");
792 mix_select_callbacks(dmix);
794 pcm->poll_fd = dmix->poll_fd;
795 pcm->poll_events = POLLIN; /* it's different than other plugins */
798 snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0);
799 snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0);
801 if (dmix->channels == UINT_MAX)
802 dmix->channels = dmix->shmptr->s.channels;
804 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
812 snd_timer_close(dmix->timer);
814 snd_pcm_direct_server_discard(dmix);
816 snd_pcm_direct_client_discard(dmix);
819 if (dmix->u.dmix.shmid_sum >= 0)
820 shm_sum_discard(dmix);
821 if (dmix->shmid >= 0) {
822 if (snd_pcm_direct_shm_discard(dmix) > 0) {
823 if (dmix->semid >= 0) {
824 if (snd_pcm_direct_semaphore_discard(dmix) < 0)
825 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
830 free(dmix->bindings);
838 /*! \page pcm_plugins
840 \section pcm_plugins_dmix Plugin: dmix
842 This plugin provides direct mixing of multiple streams. The resolution
843 for 32-bit mixing is only 24-bit. The low significant byte is filled with
844 zeros. The extra 8 bits are used for the saturation.
848 type dmix # Direct mix
849 ipc_key INT # unique IPC key
850 ipc_key_add_uid BOOL # add current uid to unique IPC key
851 ipc_perm INT # IPC permissions (octal, default 0600)
854 slave { # Slave definition
855 pcm STR # slave PCM name
857 pcm { } # slave PCM definition
858 format STR # format definition
859 rate INT # rate definition
861 period_time INT # in usec
863 period_size INT # in bytes
864 buffer_time INT # in usec
866 buffer_size INT # in bytes
867 periods INT # when buffer_size or buffer_time is not specified
869 bindings { # note: this is client independent!!!
870 N INT # maps slave channel to client channel N
872 slowptr BOOL # slow but more precise pointer updates
876 <code>ipc_key</code> specfies the unique IPC key in integer.
877 This number must be unique for each different dmix definition,
878 since the shared memory is created with this key number.
879 When <code>ipc_key_add_uid</code> is set true, the uid value is
880 added to the value set in <code>ipc_key</code>. This will
881 avoid the confliction of the same IPC key with different users
884 Note that the dmix plugin itself supports only a single configuration.
885 That is, it supports only the fixed rate (default 48000), format
886 (\c S16), channels (2), and period_time (125000).
887 For using other configuration, you have to set the value explicitly
888 in the slave PCM definition. The rate, format and channels can be
889 covered by an additional \ref pcm_plugins_dmix "plug plugin",
890 but there is only one base configuration, anyway.
892 An example configuration for setting 44100 Hz, \c S32_LE format
893 as the slave PCM of "hw:0" is like below:
897 ipc_key 321456 # any unique value
906 You can hear 48000 Hz samples still using this dmix pcm via plug plugin
909 % aplay -Dplug:dmix_44 foo_48k.wav
912 For using the dmix plugin for OSS emulation device, you have to set
913 the period and the buffer sizes in power of two. For example,
917 ipc_key 321456 # any unique value
922 period_size 1024 # must be power of 2
923 buffer_size 8192 # ditto
927 <code>period_time 0</code> must be set, too, for resetting the
928 default value. In the case of soundcards with multi-channel IO,
929 adding the bindings would help
934 0 0 # map from 0 to 0
935 1 1 # map from 1 to 1
939 so that only the first two channels are used by dmix.
940 Also, note that ICE1712 have the limited buffer size, 5513 frames
941 (corresponding to 640 kB). In this case, reduce the buffer_size
944 \subsection pcm_plugins_dmix_funcref Function reference
947 <LI>snd_pcm_dmix_open()
948 <LI>_snd_pcm_dmix_open()
954 * \brief Creates a new dmix PCM
955 * \param pcmp Returns created PCM handle
956 * \param name Name of PCM
957 * \param root Root configuration node
958 * \param conf Configuration node with dmix PCM description
959 * \param stream PCM Stream
960 * \param mode PCM Mode
961 * \warning Using of this function might be dangerous in the sense
962 * of compatibility reasons. The prototype might be freely
965 int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
966 snd_config_t *root, snd_config_t *conf,
967 snd_pcm_stream_t stream, int mode)
969 snd_config_iterator_t i, next;
970 snd_config_t *slave = NULL, *bindings = NULL, *sconf;
971 struct slave_params params;
972 int bsize, psize, ipc_key_add_uid = 0, slowptr = 0;
974 mode_t ipc_perm = 0600;
976 snd_config_for_each(i, next, conf) {
977 snd_config_t *n = snd_config_iterator_entry(i);
979 if (snd_config_get_id(n, &id) < 0)
981 if (snd_pcm_conf_generic_id(id))
983 if (strcmp(id, "ipc_key") == 0) {
985 err = snd_config_get_integer(n, &key);
987 SNDERR("The field ipc_key must be an integer type");
993 if (strcmp(id, "ipc_perm") == 0) {
996 err = snd_config_get_ascii(n, &perm);
998 SNDERR("The field ipc_perm must be a valid file permission");
1001 if (isdigit(*perm) == 0) {
1002 SNDERR("The field ipc_perm must be a valid file permission");
1005 ipc_perm = strtol(perm, &endp, 8);
1008 if (strcmp(id, "ipc_key_add_uid") == 0) {
1009 if ((err = snd_config_get_bool(n)) < 0) {
1010 SNDERR("The field ipc_key_add_uid must be a boolean type");
1013 ipc_key_add_uid = err;
1016 if (strcmp(id, "slave") == 0) {
1020 if (strcmp(id, "bindings") == 0) {
1024 if (strcmp(id, "slowptr") == 0) {
1025 err = snd_config_get_bool(n);
1031 SNDERR("Unknown field %s", id);
1035 SNDERR("slave is not defined");
1038 if (ipc_key_add_uid)
1039 ipc_key += getuid();
1041 SNDERR("Unique IPC key is not defined");
1044 /* the default settings, it might be invalid for some hardware */
1045 params.format = SND_PCM_FORMAT_S16;
1046 params.rate = 48000;
1047 params.channels = 2;
1048 params.period_time = -1;
1049 params.buffer_time = -1;
1053 err = snd_pcm_slave_conf(root, slave, &sconf, 8,
1054 SND_PCM_HW_PARAM_FORMAT, 0, ¶ms.format,
1055 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
1056 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
1057 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
1058 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
1059 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
1060 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
1061 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
1065 /* set a reasonable default */
1066 if (psize == -1 && params.period_time == -1)
1067 params.period_time = 125000; /* 0.125 seconds */
1069 /* sorry, limited features */
1070 if (params.format != SND_PCM_FORMAT_S16 &&
1071 params.format != SND_PCM_FORMAT_S32) {
1072 SNDERR("invalid format, specify s16 or s32");
1073 snd_config_delete(sconf);
1077 params.period_size = psize;
1078 params.buffer_size = bsize;
1080 err = snd_pcm_dmix_open(pcmp, name, ipc_key, ipc_perm, ¶ms, bindings, slowptr, root, sconf, stream, mode);
1082 snd_config_delete(sconf);
1086 SND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION);