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,
75 IPC_CREAT | dmix->ipc_perm);
77 if (dmix->u.dmix.shmid_sum < 0){
79 if ((tmpid = shmget(dmix->ipc_key + 1, 0, dmix->ipc_perm)) != -1)
80 if (!shmctl(tmpid, IPC_STAT, &buf))
82 /* no users so destroy the segment */
83 if (!shmctl(tmpid, IPC_RMID, NULL))
87 dmix->u.dmix.sum_buffer = shmat(dmix->u.dmix.shmid_sum, 0, 0);
88 if (dmix->u.dmix.sum_buffer == (void *) -1) {
89 shm_sum_discard(dmix);
92 mlock(dmix->u.dmix.sum_buffer, size);
96 static int shm_sum_discard(snd_pcm_direct_t *dmix)
101 if (dmix->u.dmix.shmid_sum < 0)
103 if (dmix->u.dmix.sum_buffer != (void *) -1 && shmdt(dmix->u.dmix.sum_buffer) < 0)
105 dmix->u.dmix.sum_buffer = (void *) -1;
106 if (shmctl(dmix->u.dmix.shmid_sum, IPC_STAT, &buf) < 0)
108 if (buf.shm_nattch == 0) { /* we're the last user, destroy the segment */
109 if (shmctl(dmix->u.dmix.shmid_sum, IPC_RMID, NULL) < 0)
113 dmix->u.dmix.shmid_sum = -1;
117 static void dmix_server_free(snd_pcm_direct_t *dmix)
119 /* remove the memory region */
120 shm_sum_create_or_connect(dmix);
121 shm_sum_discard(dmix);
125 * the main function of this plugin: mixing
126 * FIXME: optimize it for different architectures
129 #if defined(__i386__)
130 #include "pcm_dmix_i386.c"
131 #elif defined(__x86_64__)
132 #include "pcm_dmix_x86_64.c"
134 #include "pcm_dmix_generic.c"
137 static void mix_areas(snd_pcm_direct_t *dmix,
138 const snd_pcm_channel_area_t *src_areas,
139 const snd_pcm_channel_area_t *dst_areas,
140 snd_pcm_uframes_t src_ofs,
141 snd_pcm_uframes_t dst_ofs,
142 snd_pcm_uframes_t size)
144 volatile signed int *sum;
145 unsigned int src_step, dst_step;
146 unsigned int chn, dchn, channels;
148 channels = dmix->channels;
149 if (dmix->shmptr->s.format == SND_PCM_FORMAT_S16) {
151 volatile signed short *dst;
152 if (dmix->interleaved) {
154 * process all areas in one loop
155 * it optimizes the memory accesses for this case
157 dmix->u.dmix.mix_areas1(size * channels,
158 ((signed short *)dst_areas[0].addr) + (dst_ofs * channels),
159 ((signed short *)src_areas[0].addr) + (src_ofs * channels),
160 dmix->u.dmix.sum_buffer + (dst_ofs * channels),
161 sizeof(signed short),
162 sizeof(signed short),
166 for (chn = 0; chn < channels; chn++) {
167 dchn = dmix->bindings ? dmix->bindings[chn] : chn;
168 if (dchn >= dmix->shmptr->s.channels)
170 src_step = src_areas[chn].step / 8;
171 dst_step = dst_areas[dchn].step / 8;
172 src = (signed short *)(((char *)src_areas[chn].addr + src_areas[chn].first / 8) + (src_ofs * src_step));
173 dst = (signed short *)(((char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + (dst_ofs * dst_step));
174 sum = dmix->u.dmix.sum_buffer + channels * dst_ofs + chn;
175 dmix->u.dmix.mix_areas1(size, dst, src, sum, dst_step, src_step, channels * sizeof(signed int));
179 volatile signed int *dst;
180 if (dmix->interleaved) {
182 * process all areas in one loop
183 * it optimizes the memory accesses for this case
185 dmix->u.dmix.mix_areas2(size * channels,
186 ((signed int *)dst_areas[0].addr) + (dst_ofs * channels),
187 ((signed int *)src_areas[0].addr) + (src_ofs * channels),
188 dmix->u.dmix.sum_buffer + (dst_ofs * channels),
194 for (chn = 0; chn < channels; chn++) {
195 dchn = dmix->bindings ? dmix->bindings[chn] : chn;
196 if (dchn >= dmix->shmptr->s.channels)
198 src_step = src_areas[chn].step / 8;
199 dst_step = dst_areas[dchn].step / 8;
200 src = (signed int *)(((char *)src_areas[chn].addr + src_areas[chn].first / 8) + (src_ofs * src_step));
201 dst = (signed int *)(((char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + (dst_ofs * dst_step));
202 sum = dmix->u.dmix.sum_buffer + channels * dst_ofs + chn;
203 dmix->u.dmix.mix_areas2(size, dst, src, sum, dst_step, src_step, channels * sizeof(signed int));
209 * if no concurrent access is allowed in the mixing routines, we need to protect
210 * the area via semaphore
212 #ifdef NO_CONCURRENT_ACCESS
213 #define dmix_down_sem(dmix) snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT)
214 #define dmix_up_sem(dmix) snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT)
216 #define dmix_down_sem(dmix)
217 #define dmix_up_sem(dmix)
221 * synchronize shm ring buffer with hardware
223 static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm)
225 snd_pcm_direct_t *dmix = pcm->private_data;
226 snd_pcm_uframes_t appl_ptr, slave_appl_ptr, slave_bsize;
227 snd_pcm_uframes_t size, slave_hw_ptr;
228 const snd_pcm_channel_area_t *src_areas, *dst_areas;
230 /* calculate the size to transfer */
231 size = dmix->appl_ptr - dmix->last_appl_ptr;
234 slave_bsize = dmix->shmptr->s.buffer_size;
235 slave_hw_ptr = dmix->slave_hw_ptr;
236 /* don't write on the last active period - this area may be cleared
237 * by the driver during mix operation...
239 slave_hw_ptr -= slave_hw_ptr % dmix->shmptr->s.period_size;
240 slave_hw_ptr += slave_bsize;
241 if (dmix->slave_hw_ptr > dmix->slave_appl_ptr)
242 slave_hw_ptr -= dmix->shmptr->s.boundary;
243 if (dmix->slave_appl_ptr + size >= slave_hw_ptr)
244 size = slave_hw_ptr - dmix->slave_appl_ptr;
247 /* add sample areas here */
248 src_areas = snd_pcm_mmap_areas(pcm);
249 dst_areas = snd_pcm_mmap_areas(dmix->spcm);
250 appl_ptr = dmix->last_appl_ptr % pcm->buffer_size;
251 dmix->last_appl_ptr += size;
252 dmix->last_appl_ptr %= pcm->boundary;
253 slave_appl_ptr = dmix->slave_appl_ptr % slave_bsize;
254 dmix->slave_appl_ptr += size;
255 dmix->slave_appl_ptr %= dmix->shmptr->s.boundary;
258 snd_pcm_uframes_t transfer = size;
259 if (appl_ptr + transfer > pcm->buffer_size)
260 transfer = pcm->buffer_size - appl_ptr;
261 if (slave_appl_ptr + transfer > slave_bsize)
262 transfer = slave_bsize - slave_appl_ptr;
263 mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
267 slave_appl_ptr += transfer;
268 slave_appl_ptr %= dmix->shmptr->s.buffer_size;
269 appl_ptr += transfer;
270 appl_ptr %= pcm->buffer_size;
276 * synchronize hardware pointer (hw_ptr) with ours
278 static int _snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm, int do_slave_sync)
280 snd_pcm_direct_t *dmix = pcm->private_data;
281 snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail;
282 snd_pcm_sframes_t diff;
284 switch (snd_pcm_state(dmix->spcm)) {
285 case SND_PCM_STATE_DISCONNECTED:
286 dmix->state = SND_PCM_STATE_DISCONNECTED;
292 snd_pcm_hwsync(dmix->spcm);
293 old_slave_hw_ptr = dmix->slave_hw_ptr;
294 slave_hw_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
295 diff = slave_hw_ptr - old_slave_hw_ptr;
296 if (diff == 0) /* fast path */
298 if (dmix->state != SND_PCM_STATE_RUNNING &&
299 dmix->state != SND_PCM_STATE_DRAINING)
300 /* not really started yet - don't update hw_ptr */
303 slave_hw_ptr += dmix->shmptr->s.boundary;
304 diff = slave_hw_ptr - old_slave_hw_ptr;
306 dmix->hw_ptr += diff;
307 dmix->hw_ptr %= pcm->boundary;
308 if (pcm->stop_threshold >= pcm->boundary) /* don't care */
310 avail = snd_pcm_mmap_playback_avail(pcm);
311 if (avail > dmix->avail_max)
312 dmix->avail_max = avail;
313 if (avail >= pcm->stop_threshold) {
315 snd_timer_stop(dmix->timer);
316 gettimeofday(&tv, 0);
317 dmix->trigger_tstamp.tv_sec = tv.tv_sec;
318 dmix->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
319 if (dmix->state == SND_PCM_STATE_RUNNING) {
320 dmix->state = SND_PCM_STATE_XRUN;
323 dmix->state = SND_PCM_STATE_SETUP;
324 /* clear queue to remove pending poll events */
325 snd_pcm_direct_clear_timer_queue(dmix);
330 static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
332 snd_pcm_direct_t *dmix = pcm->private_data;
333 return _snd_pcm_dmix_sync_ptr(pcm, dmix->slowptr);
337 * plugin implementation
340 static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm)
342 snd_pcm_direct_t *dmix = pcm->private_data;
343 snd_pcm_state_t state;
344 state = snd_pcm_state(dmix->spcm);
346 case SND_PCM_STATE_SUSPENDED:
348 case SND_PCM_STATE_DISCONNECTED:
353 if (dmix->state == STATE_RUN_PENDING)
354 return SNDRV_PCM_STATE_RUNNING;
358 static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
360 snd_pcm_direct_t *dmix = pcm->private_data;
362 switch (dmix->state) {
363 case SNDRV_PCM_STATE_DRAINING:
364 case SNDRV_PCM_STATE_RUNNING:
365 snd_pcm_dmix_sync_ptr(pcm);
370 memset(status, 0, sizeof(*status));
371 status->state = snd_pcm_dmix_state(pcm);
372 status->trigger_tstamp = dmix->trigger_tstamp;
373 status->tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm);
374 status->avail = snd_pcm_mmap_playback_avail(pcm);
375 status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max;
380 static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
382 snd_pcm_direct_t *dmix = pcm->private_data;
385 switch(dmix->state) {
386 case SNDRV_PCM_STATE_DRAINING:
387 case SNDRV_PCM_STATE_RUNNING:
388 err = snd_pcm_dmix_sync_ptr(pcm);
392 case SNDRV_PCM_STATE_PREPARED:
393 case SNDRV_PCM_STATE_SUSPENDED:
394 case STATE_RUN_PENDING:
395 *delayp = snd_pcm_mmap_playback_hw_avail(pcm);
397 case SNDRV_PCM_STATE_XRUN:
399 case SNDRV_PCM_STATE_DISCONNECTED:
406 static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm)
408 snd_pcm_direct_t *dmix = pcm->private_data;
410 switch(dmix->state) {
411 case SNDRV_PCM_STATE_DRAINING:
412 case SNDRV_PCM_STATE_RUNNING:
414 //return _snd_pcm_dmix_sync_ptr(pcm, 1);
415 return snd_pcm_dmix_sync_ptr(pcm);
416 case SNDRV_PCM_STATE_PREPARED:
417 case SNDRV_PCM_STATE_SUSPENDED:
418 case STATE_RUN_PENDING:
420 case SNDRV_PCM_STATE_XRUN:
422 case SNDRV_PCM_STATE_DISCONNECTED:
429 static int snd_pcm_dmix_prepare(snd_pcm_t *pcm)
431 snd_pcm_direct_t *dmix = pcm->private_data;
433 snd_pcm_direct_check_interleave(dmix, pcm);
434 // assert(pcm->boundary == dmix->shmptr->s.boundary); /* for sure */
435 dmix->state = SND_PCM_STATE_PREPARED;
436 dmix->appl_ptr = dmix->last_appl_ptr = 0;
438 return snd_pcm_direct_set_timer_params(dmix);
441 static int snd_pcm_dmix_reset(snd_pcm_t *pcm)
443 snd_pcm_direct_t *dmix = pcm->private_data;
444 dmix->hw_ptr %= pcm->period_size;
445 dmix->appl_ptr = dmix->last_appl_ptr = dmix->hw_ptr;
446 dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
450 static int snd_pcm_dmix_start_timer(snd_pcm_direct_t *dmix)
454 snd_pcm_hwsync(dmix->spcm);
455 dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
456 err = snd_timer_start(dmix->timer);
459 dmix->state = SND_PCM_STATE_RUNNING;
463 static int snd_pcm_dmix_start(snd_pcm_t *pcm)
465 snd_pcm_direct_t *dmix = pcm->private_data;
466 snd_pcm_sframes_t avail;
470 if (dmix->state != SND_PCM_STATE_PREPARED)
472 avail = snd_pcm_mmap_playback_hw_avail(pcm);
474 dmix->state = STATE_RUN_PENDING;
478 if ((err = snd_pcm_dmix_start_timer(dmix)) < 0)
480 snd_pcm_dmix_sync_area(pcm);
482 gettimeofday(&tv, 0);
483 dmix->trigger_tstamp.tv_sec = tv.tv_sec;
484 dmix->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
488 static int snd_pcm_dmix_drop(snd_pcm_t *pcm)
490 snd_pcm_direct_t *dmix = pcm->private_data;
491 if (dmix->state == SND_PCM_STATE_OPEN)
493 snd_pcm_direct_timer_stop(dmix);
494 dmix->state = SND_PCM_STATE_SETUP;
498 static int snd_pcm_dmix_drain(snd_pcm_t *pcm)
500 snd_pcm_direct_t *dmix = pcm->private_data;
501 snd_pcm_uframes_t stop_threshold;
504 if (dmix->state == SND_PCM_STATE_OPEN)
506 if (pcm->mode & SND_PCM_NONBLOCK)
508 if (dmix->state == SND_PCM_STATE_PREPARED) {
509 if (snd_pcm_mmap_playback_hw_avail(pcm) > 0)
510 snd_pcm_dmix_start(pcm);
512 snd_pcm_dmix_drop(pcm);
516 stop_threshold = pcm->stop_threshold;
517 if (pcm->stop_threshold > pcm->buffer_size)
518 pcm->stop_threshold = pcm->buffer_size;
519 dmix->state = SND_PCM_STATE_DRAINING;
521 err = snd_pcm_dmix_sync_ptr(pcm);
523 snd_pcm_dmix_drop(pcm);
526 if (dmix->state == SND_PCM_STATE_DRAINING) {
527 snd_pcm_dmix_sync_area(pcm);
528 snd_pcm_wait_nocheck(pcm, -1);
529 snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */
531 } while (dmix->state == SND_PCM_STATE_DRAINING);
532 pcm->stop_threshold = stop_threshold;
536 static int snd_pcm_dmix_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
541 static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_uframes_t frames ATTRIBUTE_UNUSED)
544 /* FIXME: substract samples from the mix ring buffer, too? */
545 snd_pcm_mmap_appl_backward(pcm, frames);
552 static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
554 snd_pcm_sframes_t avail;
556 avail = snd_pcm_mmap_playback_avail(pcm);
559 if (frames > (snd_pcm_uframes_t)avail)
561 snd_pcm_mmap_appl_forward(pcm, frames);
565 static int snd_pcm_dmix_resume(snd_pcm_t *pcm)
567 snd_pcm_direct_t *dmix = pcm->private_data;
568 snd_pcm_resume(dmix->spcm);
572 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)
577 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)
582 static int snd_pcm_dmix_close(snd_pcm_t *pcm)
584 snd_pcm_direct_t *dmix = pcm->private_data;
587 snd_timer_close(dmix->timer);
588 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
589 snd_pcm_close(dmix->spcm);
591 snd_pcm_direct_server_discard(dmix);
593 snd_pcm_direct_client_discard(dmix);
594 shm_sum_discard(dmix);
595 if (snd_pcm_direct_shm_discard(dmix) > 0) {
596 if (snd_pcm_direct_semaphore_discard(dmix) < 0)
597 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
599 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
602 free(dmix->bindings);
603 pcm->private_data = NULL;
608 static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
609 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
610 snd_pcm_uframes_t size)
612 snd_pcm_direct_t *dmix = pcm->private_data;
615 switch (snd_pcm_state(dmix->spcm)) {
616 case SND_PCM_STATE_XRUN:
618 case SND_PCM_STATE_SUSPENDED:
625 snd_pcm_mmap_appl_forward(pcm, size);
626 if (dmix->state == STATE_RUN_PENDING) {
627 if ((err = snd_pcm_dmix_start_timer(dmix)) < 0)
629 } else if (dmix->state == SND_PCM_STATE_RUNNING ||
630 dmix->state == SND_PCM_STATE_DRAINING)
631 //_snd_pcm_dmix_sync_ptr(pcm, 1);
632 snd_pcm_dmix_sync_ptr(pcm);
633 if (dmix->state == SND_PCM_STATE_RUNNING ||
634 dmix->state == SND_PCM_STATE_DRAINING) {
635 /* ok, we commit the changes after the validation of area */
636 /* it's intended, although the result might be crappy */
637 snd_pcm_dmix_sync_area(pcm);
638 /* clear timer queue to avoid a bogus return from poll */
639 if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
640 snd_pcm_direct_clear_timer_queue(dmix);
645 static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm)
647 snd_pcm_direct_t *dmix = pcm->private_data;
649 if (dmix->state == SND_PCM_STATE_RUNNING ||
650 dmix->state == SND_PCM_STATE_DRAINING)
651 snd_pcm_dmix_sync_ptr(pcm);
652 return snd_pcm_mmap_playback_avail(pcm);
655 static int snd_pcm_dmix_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
657 snd_pcm_direct_t *dmix = pcm->private_data;
658 if (dmix->state == SND_PCM_STATE_RUNNING)
659 snd_pcm_dmix_sync_area(pcm);
660 return snd_pcm_direct_poll_revents(pcm, pfds, nfds, revents);
664 static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out)
666 snd_pcm_direct_t *dmix = pcm->private_data;
668 snd_output_printf(out, "Direct Stream Mixing PCM\n");
670 snd_output_printf(out, "\nIts setup is:\n");
671 snd_pcm_dump_setup(pcm, out);
674 snd_pcm_dump(dmix->spcm, out);
677 static snd_pcm_ops_t snd_pcm_dmix_ops = {
678 .close = snd_pcm_dmix_close,
679 .info = snd_pcm_direct_info,
680 .hw_refine = snd_pcm_direct_hw_refine,
681 .hw_params = snd_pcm_direct_hw_params,
682 .hw_free = snd_pcm_direct_hw_free,
683 .sw_params = snd_pcm_direct_sw_params,
684 .channel_info = snd_pcm_direct_channel_info,
685 .dump = snd_pcm_dmix_dump,
686 .nonblock = snd_pcm_direct_nonblock,
687 .async = snd_pcm_direct_async,
688 .poll_revents = snd_pcm_dmix_poll_revents,
689 .mmap = snd_pcm_direct_mmap,
690 .munmap = snd_pcm_direct_munmap,
693 static snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
694 .status = snd_pcm_dmix_status,
695 .state = snd_pcm_dmix_state,
696 .hwsync = snd_pcm_dmix_hwsync,
697 .delay = snd_pcm_dmix_delay,
698 .prepare = snd_pcm_dmix_prepare,
699 .reset = snd_pcm_dmix_reset,
700 .start = snd_pcm_dmix_start,
701 .drop = snd_pcm_dmix_drop,
702 .drain = snd_pcm_dmix_drain,
703 .pause = snd_pcm_dmix_pause,
704 .rewind = snd_pcm_dmix_rewind,
705 .forward = snd_pcm_dmix_forward,
706 .resume = snd_pcm_dmix_resume,
710 .writei = snd_pcm_mmap_writei,
711 .writen = snd_pcm_mmap_writen,
712 .readi = snd_pcm_dmix_readi,
713 .readn = snd_pcm_dmix_readn,
714 .avail_update = snd_pcm_dmix_avail_update,
715 .mmap_commit = snd_pcm_dmix_mmap_commit,
719 * \brief Creates a new dmix PCM
720 * \param pcmp Returns created PCM handle
721 * \param name Name of PCM
722 * \param ipc_key IPC key for semaphore and shared memory
723 * \param ipc_perm IPC permissions for semaphore and shared memory
724 * \param params Parameters for slave
725 * \param bindings Channel bindings
726 * \param slowptr Slow but more precise pointer updates
727 * \param root Configuration root
728 * \param sconf Slave configuration
729 * \param stream PCM Direction (stream)
730 * \param mode PCM Mode
731 * \retval zero on success otherwise a negative error code
732 * \warning Using of this function might be dangerous in the sense
733 * of compatibility reasons. The prototype might be freely
736 int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
737 key_t ipc_key, mode_t ipc_perm,
738 struct slave_params *params,
739 snd_config_t *bindings,
741 snd_config_t *root, snd_config_t *sconf,
742 snd_pcm_stream_t stream, int mode)
744 snd_pcm_t *pcm = NULL, *spcm = NULL;
745 snd_pcm_direct_t *dmix = NULL;
746 int ret, first_instance;
747 int fail_sem_loop = 10;
751 if (stream != SND_PCM_STREAM_PLAYBACK) {
752 SNDERR("The dmix plugin supports only playback stream");
756 dmix = calloc(1, sizeof(snd_pcm_direct_t));
762 ret = snd_pcm_direct_parse_bindings(dmix, bindings);
766 dmix->ipc_key = ipc_key;
767 dmix->ipc_perm = ipc_perm;
771 ret = snd_pcm_new(&pcm, dmix->type = SND_PCM_TYPE_DMIX, name, stream, mode);
777 ret = snd_pcm_direct_semaphore_create_or_connect(dmix);
779 SNDERR("unable to create IPC semaphore");
782 ret = snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
784 snd_pcm_direct_semaphore_discard(dmix);
785 if (--fail_sem_loop <= 0)
792 first_instance = ret = snd_pcm_direct_shm_create_or_connect(dmix);
794 SNDERR("unable to create IPC shm instance");
798 pcm->ops = &snd_pcm_dmix_ops;
799 pcm->fast_ops = &snd_pcm_dmix_fast_ops;
800 pcm->private_data = dmix;
801 dmix->state = SND_PCM_STATE_OPEN;
802 dmix->slowptr = slowptr;
803 dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
805 if (first_instance) {
806 ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode);
808 SNDERR("unable to open slave");
812 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
813 SNDERR("dmix plugin can be only connected to hw plugin");
818 ret = snd_pcm_direct_initialize_slave(dmix, spcm, params);
820 SNDERR("unable to initialize slave");
826 dmix->server_free = dmix_server_free;
828 ret = snd_pcm_direct_server_create(dmix);
830 SNDERR("unable to create server");
834 dmix->shmptr->type = spcm->type;
836 ret = snd_pcm_direct_client_connect(dmix);
838 SNDERR("unable to connect client");
842 ret = snd_pcm_hw_open_fd(&spcm, "dmix_client", dmix->hw_fd, 0, 0);
844 SNDERR("unable to open hardware");
848 spcm->donot_close = 1;
850 spcm->buffer_size = dmix->shmptr->s.buffer_size;
851 spcm->sample_bits = dmix->shmptr->s.sample_bits;
852 spcm->channels = dmix->shmptr->s.channels;
853 spcm->format = dmix->shmptr->s.format;
854 spcm->boundary = dmix->shmptr->s.boundary;
855 spcm->info = dmix->shmptr->s.info;
856 ret = snd_pcm_mmap(spcm);
858 SNDERR("unable to mmap channels");
864 ret = shm_sum_create_or_connect(dmix);
866 SNDERR("unable to initialize sum ring buffer");
870 ret = snd_pcm_direct_initialize_poll_fd(dmix);
872 SNDERR("unable to initialize poll_fd");
876 mix_select_callbacks(dmix);
878 pcm->poll_fd = dmix->poll_fd;
879 pcm->poll_events = POLLIN; /* it's different than other plugins */
882 snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0);
883 snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0);
885 if (dmix->channels == UINT_MAX)
886 dmix->channels = dmix->shmptr->s.channels;
888 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
896 snd_timer_close(dmix->timer);
898 snd_pcm_direct_server_discard(dmix);
900 snd_pcm_direct_client_discard(dmix);
903 if (dmix->u.dmix.shmid_sum >= 0)
904 shm_sum_discard(dmix);
905 if (dmix->shmid >= 0) {
906 if (snd_pcm_direct_shm_discard(dmix) > 0) {
907 if (dmix->semid >= 0) {
908 if (snd_pcm_direct_semaphore_discard(dmix) < 0)
909 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
914 free(dmix->bindings);
922 /*! \page pcm_plugins
924 \section pcm_plugins_dmix Plugin: dmix
926 This plugin provides direct mixing of multiple streams. The resolution
927 for 32-bit mixing is only 24-bit. The low significant byte is filled with
928 zeros. The extra 8 bits are used for the saturation.
932 type dmix # Direct mix
933 ipc_key INT # unique IPC key
934 ipc_key_add_uid BOOL # add current uid to unique IPC key
935 ipc_perm INT # IPC permissions (octal, default 0600)
938 slave { # Slave definition
939 pcm STR # slave PCM name
941 pcm { } # slave PCM definition
942 format STR # format definition
943 rate INT # rate definition
945 period_time INT # in usec
947 period_size INT # in bytes
948 buffer_time INT # in usec
950 buffer_size INT # in bytes
951 periods INT # when buffer_size or buffer_time is not specified
953 bindings { # note: this is client independent!!!
954 N INT # maps slave channel to client channel N
956 slowptr BOOL # slow but more precise pointer updates
960 <code>ipc_key</code> specfies the unique IPC key in integer.
961 This number must be unique for each different dmix definition,
962 since the shared memory is created with this key number.
963 When <code>ipc_key_add_uid</code> is set true, the uid value is
964 added to the value set in <code>ipc_key</code>. This will
965 avoid the confliction of the same IPC key with different users
968 Note that the dmix plugin itself supports only a single configuration.
969 That is, it supports only the fixed rate (default 48000), format
970 (\c S16), channels (2), and period_time (125000).
971 For using other configuration, you have to set the value explicitly
972 in the slave PCM definition. The rate, format and channels can be
973 covered by an additional \ref pcm_plugins_dmix "plug plugin",
974 but there is only one base configuration, anyway.
976 An example configuration for setting 44100 Hz, \c S32_LE format
977 as the slave PCM of "hw:0" is like below:
981 ipc_key 321456 # any unique value
990 You can hear 48000 Hz samples still using this dmix pcm via plug plugin
993 % aplay -Dplug:dmix_44 foo_48k.wav
996 For using the dmix plugin for OSS emulation device, you have to set
997 the period and the buffer sizes in power of two. For example,
1001 ipc_key 321456 # any unique value
1002 ipc_key_add_uid true
1006 period_size 1024 # must be power of 2
1007 buffer_size 8192 # ditto
1011 <code>period_time 0</code> must be set, too, for resetting the
1012 default value. In the case of soundcards with multi-channel IO,
1013 adding the bindings would help
1018 0 0 # map from 0 to 0
1019 1 1 # map from 1 to 1
1023 so that only the first two channels are used by dmix.
1024 Also, note that ICE1712 have the limited buffer size, 5513 frames
1025 (corresponding to 640 kB). In this case, reduce the buffer_size
1028 \subsection pcm_plugins_dmix_funcref Function reference
1031 <LI>snd_pcm_dmix_open()
1032 <LI>_snd_pcm_dmix_open()
1038 * \brief Creates a new dmix PCM
1039 * \param pcmp Returns created PCM handle
1040 * \param name Name of PCM
1041 * \param root Root configuration node
1042 * \param conf Configuration node with dmix PCM description
1043 * \param stream PCM Stream
1044 * \param mode PCM Mode
1045 * \warning Using of this function might be dangerous in the sense
1046 * of compatibility reasons. The prototype might be freely
1047 * changed in future.
1049 int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
1050 snd_config_t *root, snd_config_t *conf,
1051 snd_pcm_stream_t stream, int mode)
1053 snd_config_iterator_t i, next;
1054 snd_config_t *slave = NULL, *bindings = NULL, *sconf;
1055 struct slave_params params;
1056 int bsize, psize, ipc_key_add_uid = 0, slowptr = 0;
1058 mode_t ipc_perm = 0600;
1060 snd_config_for_each(i, next, conf) {
1061 snd_config_t *n = snd_config_iterator_entry(i);
1063 if (snd_config_get_id(n, &id) < 0)
1065 if (snd_pcm_conf_generic_id(id))
1067 if (strcmp(id, "ipc_key") == 0) {
1069 err = snd_config_get_integer(n, &key);
1071 SNDERR("The field ipc_key must be an integer type");
1077 if (strcmp(id, "ipc_perm") == 0) {
1080 err = snd_config_get_ascii(n, &perm);
1082 SNDERR("The field ipc_perm must be a valid file permission");
1085 if (isdigit(*perm) == 0) {
1086 SNDERR("The field ipc_perm must be a valid file permission");
1089 ipc_perm = strtol(perm, &endp, 8);
1092 if (strcmp(id, "ipc_key_add_uid") == 0) {
1093 if ((err = snd_config_get_bool(n)) < 0) {
1094 SNDERR("The field ipc_key_add_uid must be a boolean type");
1097 ipc_key_add_uid = err;
1100 if (strcmp(id, "slave") == 0) {
1104 if (strcmp(id, "bindings") == 0) {
1108 if (strcmp(id, "slowptr") == 0) {
1109 err = snd_config_get_bool(n);
1115 SNDERR("Unknown field %s", id);
1119 SNDERR("slave is not defined");
1122 if (ipc_key_add_uid)
1123 ipc_key += getuid();
1125 SNDERR("Unique IPC key is not defined");
1128 /* the default settings, it might be invalid for some hardware */
1129 params.format = SND_PCM_FORMAT_S16;
1130 params.rate = 48000;
1131 params.channels = 2;
1132 params.period_time = -1;
1133 params.buffer_time = -1;
1137 err = snd_pcm_slave_conf(root, slave, &sconf, 8,
1138 SND_PCM_HW_PARAM_FORMAT, 0, ¶ms.format,
1139 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
1140 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
1141 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
1142 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
1143 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
1144 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
1145 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
1149 /* set a reasonable default */
1150 if (psize == -1 && params.period_time == -1)
1151 params.period_time = 125000; /* 0.125 seconds */
1153 /* sorry, limited features */
1154 if (params.format != SND_PCM_FORMAT_S16 &&
1155 params.format != SND_PCM_FORMAT_S32) {
1156 SNDERR("invalid format, specify s16 or s32");
1157 snd_config_delete(sconf);
1161 params.period_size = psize;
1162 params.buffer_size = bsize;
1164 err = snd_pcm_dmix_open(pcmp, name, ipc_key, ipc_perm, ¶ms, bindings, slowptr, root, sconf, stream, mode);
1166 snd_config_delete(sconf);
1170 SND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION);